merge b2g-inbound to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 20 Mar 2014 14:07:58 +0100
changeset 174524 cf485c48b52f283ceab119341b965dcf75234721
parent 174468 2d20e6067412c12c6788397108dc7103037f07be (current diff)
parent 174523 9b44086c1d1c0c449cbf7d18836ffa862ff60c24 (diff)
child 174525 131277cc768d8c9fcceeb018188432808d11a731
child 174564 41265909a0fa23feb5cbc80638f6fe4efda5492a
child 174591 e360e47421248a4bef03bed841b4f9fa19b2a9c0
push id5801
push usercbook@mozilla.com
push dateThu, 20 Mar 2014 13:29:21 +0000
treeherderfx-team@131277cc768d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.0a1
merge b2g-inbound to mozilla-central
b2g/app/b2g.js
configure.in
dom/ipc/ContentParent.cpp
dom/mobilemessage/src/MessageUtils.h
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/moz.build
hal/Hal.cpp
hal/HalTypes.h
hal/gonk/GonkHal.cpp
testing/mochitest/b2g-debug.json
testing/mochitest/b2g-desktop.json
testing/mochitest/b2g.json
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -645,16 +645,19 @@ pref("dom.ipc.processPriorityManager.bac
 // The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is
 // okay, kernel will still kill processes with larger OomScoreAdjust first even
 // its OomScoreAdjust don't have a corresponding KillUnderKB.
 
 pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0);
 pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096);
 pref("hal.processPriorityManager.gonk.MASTER.Nice", 0);
 
+pref("hal.processPriorityManager.gonk.PREALLOC.OomScoreAdjust", 67);
+pref("hal.processPriorityManager.gonk.PREALLOC.Nice", 18);
+
 pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67);
 pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120);
 pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.Nice", 0);
 
 pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134);
 pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144);
 pref("hal.processPriorityManager.gonk.FOREGROUND.Nice", 1);
 
new file mode 100644
--- /dev/null
+++ b/b2g/chrome/content/desktop.css
@@ -0,0 +1,59 @@
+#controls {
+  position: absolute;
+  left: 0;
+  bottom:0;
+  right: 0;
+  height: 30px;
+  background-color: -moz-dialog;
+}
+
+#home-button {
+  margin: auto;
+  margin-top: 3px;
+  width: 24px;
+  height: 24px;
+  background: #eee url("images/desktop/home-black.png") center no-repeat;
+  border: 1px solid #888;
+  border-radius: 12px;
+  display: block;
+}
+
+#home-button::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+
+#home-button:hover {
+  background-image: url("images/desktop/home-white.png");
+  background-color: #ccc;
+  border-color: #555;
+}
+
+#home-button.active {
+  background-image: url("images/desktop/home-white.png");
+  background-color: #888;
+  border-color: black;
+}
+
+#rotate-button {
+  position: absolute;
+  top: 3px;
+  bottom: 3px;
+  right: 3px;
+  width: 24px;
+  height: 24px;
+  background: #eee url("images/desktop/rotate.png") center no-repeat;
+  border: 1px solid #888;
+  border-radius: 12px;
+  display: block;
+}
+
+#rotate-button:hover {
+  background-color: #ccc;
+  border-color: #555;
+}
+
+#rotate-button.active {
+  background-color: #888;
+  border-color: black;
+}
--- a/b2g/chrome/content/desktop.js
+++ b/b2g/chrome/content/desktop.js
@@ -1,17 +1,52 @@
 /* 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/. */
 
-window.addEventListener("ContentStart", function(evt) {
-  // Enable touch event shim on desktop that translates mouse events
-  // into touch ones
-  let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {})
+// Enable touch event shim on desktop that translates mouse events
+// into touch ones
+function enableTouch() {
+  let require = Cu.import('resource://gre/modules/devtools/Loader.jsm', {})
                   .devtools.require;
-  let { TouchEventHandler } = require("devtools/touch-events");
+  let { TouchEventHandler } = require('devtools/touch-events');
   let chromeEventHandler = window.QueryInterface(Ci.nsIInterfaceRequestor)
                                  .getInterface(Ci.nsIWebNavigation)
                                  .QueryInterface(Ci.nsIDocShell)
                                  .chromeEventHandler || window;
   let touchEventHandler = new TouchEventHandler(chromeEventHandler);
   touchEventHandler.start();
+}
+
+function setupButtons() {
+  let homeButton = document.getElementById('home-button');
+  if (!homeButton) {
+    // The toolbar only exists in b2g desktop build with
+    // FXOS_SIMULATOR turned on.
+    return;
+  }
+  // The touch event helper is enabled on shell.html document,
+  // so that click events are delayed and it is better to
+  // listen for touch events.
+  homeButton.addEventListener('touchstart', function() {
+    shell.sendChromeEvent({type: 'home-button-press'});
+    homeButton.classList.add('active');
+  });
+  homeButton.addEventListener('touchend', function() {
+    shell.sendChromeEvent({type: 'home-button-release'});
+    homeButton.classList.remove('active');
+  });
+
+  Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm");
+  let rotateButton = document.getElementById('rotate-button');
+  rotateButton.addEventListener('touchstart', function () {
+    rotateButton.classList.add('active');
+  });
+  rotateButton.addEventListener('touchend', function() {
+    GlobalSimulatorScreen.flipScreen();
+    rotateButton.classList.remove('active');
+  });
+}
+
+window.addEventListener('ContentStart', function() {
+  enableTouch();
+  setupButtons();
 });
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c51187ed49e128d49b64adabf003fd140411477d
GIT binary patch
literal 331
zc$@)C0kr;!P)<h;3K|Lk000e1NJLTq000aC000aK1^@s6R&`wG00006VoOIv0RI60
z0RN!9r;`8x0RTxvK~yNutx&s7#6T3BdER{{^R7fdf-DnI05J(Y5F7<SjA-K|L<|Ku
zL81gIfD*6_2^reVTKl{t=aU6@BH<<PH}ghsfPaY0Ik$AqEdgXdmz+06QFvp_gSGYy
z0Q$av9){sEgz)u?P!z?Hsy-TH4pnsp05QgF7>17+<9P_-4U?qz{xr|?Cu{A#wRR;U
ziDX)5Cn5_~ed)UHJ@ejQsp`G8RwwXAp2V88M{=R6fhnb904G&d-H{x(xsXzlrfIGL
zyl#Fd%koo1#*`A9rnv!ts;X{Drg0plZQBC?kl7VZnPg3}p3f$nY?0@-dMDwpm|we?
dxl`|&eFNOMWnB{Vk-q={002ovPDHLkV1gK|iDUo(
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..43379d0e949ccb5b6664f6e230f47d448e723254
GIT binary patch
literal 276
zc%17D@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kwj^(N7l!{JxM1({$v}~lo-U3d
z8t0ex8|EEy5ODp!eJ4YxMo{2|bt&5|{j*%W=V}E_X)a({m*BmxRqzyVg524>6je3N
zAD1%Rjo+Vt<I&HxqVc=T*ZL1a77X#0d<Q<s?dj{VQ#yBmqerl?uR|_EeBG%J-AfiP
zN%s_2XqZrPa%*y0$^+4g$t_E=>y~d?5;ZCJ{oJ5i3}+2^=2yPbzqu~REBf|cb@QH^
z54Po&Pr6ciw_PPCd|P;Gtl^x7*IOdnZmi3-ua&p`{CsE3cb@vJz)8z8x7p7w-YUIt
Xdi(biYu9-KJ;mVZ>gTe~DWM4f`2KW(
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9da1b5674dbbf78ed3446dac86f43e81f8e687be
GIT binary patch
literal 657
zc$@)|0&e|@P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAH}3<e*d*!BPb0v<_3
zK~y-)rIXD|R8bhlf9K8_7zdgUbu29`TV)|3>7dy^U?GkpmX(o7i(2W%Hf@EVHf^GX
zAyOh{R+>X&LQom@F&aULQ6?BnTH4H=FSQx(+!ozHN+s!qhqHKjp7T8KIj_)lo&PCe
zw&!h{l$Z%v01L1z|7b|S2DktRU<Oiv3d{phKmvO!J@pO#{+?@c71;_D-01A`^xhpf
z^loC(8HvWscH5Rz(Z0g)(c0?gXB!)a0L%I23oVbIjO+#mh1s4*VkTgX#pA_I=UQ3^
zeEuCk8qf_01B$2Wa4^&9Sn0UgoeyY9HF!xR)u03ly~oeA`TWCM0d0f$Cgaoql4|gZ
z1ngZseIB2GI15MuY|q`M73|uneOp*iK79PNdQN|dOCa}lUw;XZ%yDI>uU>AOtE;IR
z10sOq+33r1Z+&A{BpMTIS&~4`*qgT&DP^knR{K;%x%-ZQDIGL)iXQle4o0G}-!oZL
zAme)|oc2~9S*j>=4+$7g>uA89=GKc1*V{Yo##6GMz)E&j=8rOWNeGw*;y`BYiKe>2
zhmW#><#m4{M5O@rK=FRnWK!mV#f<z?eQ_p`y4T%tA9xQq0c8#TEHEvBxw@LFv60bN
zF5So}1PNfmaHOnbAO$2Og89=Yk3D_ydb~^+Su^rWH6USN<7HZj1ceT^FSB25p-?#P
rt~?dq^foSi4k&=sL9_n4{h#Y6+p5l88?BLt00000NkvXXu0mjfSMwh@
--- a/b2g/chrome/content/screen.js
+++ b/b2g/chrome/content/screen.js
@@ -13,17 +13,17 @@ window.addEventListener('ContentStart', 
   // The <browser> element inside it
   let browser = document.getElementById('systemapp');
 
   // Figure out the native resolution of the screen
   let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
     .getInterface(Components.interfaces.nsIDOMWindowUtils);
   let hostDPI = windowUtils.displayDPI;
 
-  let DEFAULT_SCREEN = "320x480";
+  let DEFAULT_SCREEN = '320x480';
 
   // This is a somewhat random selection of named screens.
   // Add more to this list when we support more hardware.
   // Data from: http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density
   let screens = {
     iphone: {
       name: 'Apple iPhone', width:320, height:480,  dpi:163
     },
@@ -115,54 +115,111 @@ window.addEventListener('ContentStart', 
       dpi = parseInt(match[4], 10);
     else    // If no DPI, use the actual dpi of the host screen
       dpi = hostDPI;
 
     // If any of the values came out 0 or NaN or undefined, display usage
     if (!width || !height || !dpi)
       usage();
   }
-  
-  // In order to do rescaling, we set the <browser> tag to the specified
-  // width and height, and then use a CSS transform to scale it so that
-  // it appears at the correct size on the host display.  We also set
-  // the size of the <window> element to that scaled target size.
-  let scale = rescale ? hostDPI / dpi : 1;
+
+  Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm");
+  function resize(width, height, dpi, shouldFlip) {
+    GlobalSimulatorScreen.width = width;
+    GlobalSimulatorScreen.height = height;
+
+    // In order to do rescaling, we set the <browser> tag to the specified
+    // width and height, and then use a CSS transform to scale it so that
+    // it appears at the correct size on the host display.  We also set
+    // the size of the <window> element to that scaled target size.
+    let scale = rescale ? hostDPI / dpi : 1;
+
+    // Set the window width and height to desired size plus chrome
+    // Include the size of the toolbox displayed under the system app
+    let controls = document.getElementById('controls');
+    let controlsHeight = 0;
+    if (controls) {
+      controlsHeight = controls.getBoundingClientRect().height;
+    }
+    let chromewidth = window.outerWidth - window.innerWidth;
+    let chromeheight = window.outerHeight - window.innerHeight + controlsHeight;
+    window.resizeTo(Math.round(width * scale) + chromewidth,
+                    Math.round(height * scale) + chromeheight);
 
-  // Set the window width and height to desired size plus chrome
-  let chromewidth = window.outerWidth - window.innerWidth;
-  let chromeheight = window.outerHeight - window.innerHeight;
-  window.resizeTo(Math.round(width * scale) + chromewidth,
-                  Math.round(height * scale) + chromeheight);
+    let frameWidth = width, frameHeight = height;
+    if (shouldFlip) {
+      frameWidth = height;
+      frameHeight = width;
+    }
+
+    // Set the browser element to the full unscaled size of the screen
+    let style = browser.style;
+    style.width = style.minWidth = style.maxWidth =
+      frameWidth + 'px';
+    style.height = style.minHeight = style.maxHeight =
+      frameHeight + 'px';
+    browser.setAttribute('flex', '0');  // Don't let it stretch
+
+    style.transformOrigin = '';
+    style.transform = '';
 
-  // Set the browser element to the full unscaled size of the screen
-  browser.style.width = browser.style.minWidth = browser.style.maxWidth =
-    width + 'px';
-  browser.style.height = browser.style.minHeight = browser.style.maxHeight =
-    height + 'px';
-  browser.setAttribute('flex', '0');  // Don't let it stretch
+    // Now scale the browser element as needed
+    if (scale !== 1) {
+      style.transformOrigin = 'top left';
+      style.transform += ' scale(' + scale + ',' + scale + ')';
+    }
 
-  // Now scale the browser element as needed
-  if (scale !== 1) {
-    browser.style.transformOrigin = 'top left';
-    browser.style.transform = 'scale(' + scale + ',' + scale + ')';
+    if (shouldFlip) {
+      // Display the system app with a 90° clockwise rotation
+      let shift = Math.floor(Math.abs(frameWidth-frameHeight) / 2);
+      style.transform +=
+        ' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)';
+    }
+
+    // Set the pixel density that we want to simulate.
+    // This doesn't change the on-screen size, but makes
+    // CSS media queries and mozmm units work right.
+    Services.prefs.setIntPref('layout.css.dpi', dpi);
   }
 
-  // Set the pixel density that we want to simulate.
-  // This doesn't change the on-screen size, but makes
-  // CSS media queries and mozmm units work right.
-  Services.prefs.setIntPref('layout.css.dpi', dpi);
+  // Resize on startup
+  resize(width, height, dpi, false);
+
+  let defaultOrientation = width < height ? 'portrait' : 'landscape';
+
+  // Then resize on each rotation button click,
+  // or when the system app lock/unlock the orientation
+  Services.obs.addObserver(function orientationChangeListener(subject) {
+    let screen = subject.wrappedJSObject;
+    let { mozOrientation, screenOrientation } = screen;
+
+    let newWidth = width;
+    let newHeight = height;
+    // If we have an orientation different than the startup one,
+    // we switch the sizes
+    if (screenOrientation != defaultOrientation) {
+      newWidth = height;
+      newHeight = width;
+    }
+
+    // If the current app doesn't supports the current screen orientation
+    // still resize the window, but rotate its frame so that
+    // it is displayed rotated on the side
+    let shouldFlip = mozOrientation != screenOrientation;
+
+    resize(newWidth, newHeight, dpi, shouldFlip);
+  }, 'simulator-adjust-window-size', false);
 
   // A utility function like console.log() for printing to the terminal window
   // Uses dump(), but enables it first, if necessary
   function print() {
     let dump_enabled =
       Services.prefs.getBoolPref('browser.dom.window.dump.enabled');
 
-    if (!dump_enabled) 
+    if (!dump_enabled)
       Services.prefs.setBoolPref('browser.dom.window.dump.enabled', true);
 
     dump(Array.prototype.join.call(arguments, ' ') + '\n');
 
     if (!dump_enabled) 
       Services.prefs.setBoolPref('browser.dom.window.dump.enabled', false);
   }
 
--- a/b2g/chrome/content/shell.html
+++ b/b2g/chrome/content/shell.html
@@ -7,17 +7,21 @@
       id="shell"
       windowtype="navigator:browser"
 #ifdef ANDROID
       sizemode="fullscreen"
 #endif
       >
 
 <head>
-  <link rel="stylesheet" href="shell.css" type="text/css" media="all" />
+  <link rel="stylesheet" href="shell.css" type="text/css">
+#ifdef FXOS_SIMULATOR
+  <link rel="stylesheet" href="desktop.css" type="text/css">
+#endif
+
   <script type="application/javascript;version=1.8"
           src="chrome://b2g/content/settings.js"> </script>
   <script type="application/javascript;version=1.8"
           src="chrome://b2g/content/shell.js"> </script>
 
 #ifndef MOZ_WIDGET_GONK
   <!-- various task that has to happen only on desktop -->
   <script type="application/javascript;version=1.8"
@@ -26,17 +30,25 @@
   <script type="application/javascript;version=1.8"
           src="chrome://b2g/content/screen.js"> </script>
   <!-- this script handles the "runapp" argument for desktop builds -->
   <script type="application/javascript;version=1.8"
           src="chrome://b2g/content/runapp.js"> </script>
 #endif
 </head>
   <body id="container">
-#ifdef MOZ_WIDGET_COCOA
+#ifdef FXOS_SIMULATOR
+    <!--
+     Some additional buttons are displayed on desktop to fake hardware buttons.
+    -->
+    <footer id="controls">
+      <button id="home-button"></button>
+      <button id="rotate-button"></button>
+    </footer>
+#elifdef MOZ_WIDGET_COCOA
     <!--
      If the document is empty at startup, we don't display the window
      at all on Mac OS...
     -->
     <h1 id="placeholder">wtf mac os!</h1>
 #endif
     <!-- The html:iframe containing the UI is created here. -->
   </body>
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -298,17 +298,21 @@ var shell = {
     systemAppFrame.setAttribute('id', 'systemapp');
     systemAppFrame.setAttribute('mozbrowser', 'true');
     systemAppFrame.setAttribute('mozapp', manifestURL);
     systemAppFrame.setAttribute('allowfullscreen', 'true');
     systemAppFrame.setAttribute('style', "overflow: hidden; height: 100%; width: 100%; border: none;");
     systemAppFrame.setAttribute('src', "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;");
     let container = document.getElementById('container');
 #ifdef MOZ_WIDGET_COCOA
-    container.removeChild(document.getElementById('placeholder'));
+    // See shell.html
+    let hotfix = document.getElementById('placeholder');
+    if (hotfix) {
+      container.removeChild(hotfix);
+    }
 #endif
     container.appendChild(systemAppFrame);
 
     systemAppFrame.contentWindow
                   .QueryInterface(Ci.nsIInterfaceRequestor)
                   .getInterface(Ci.nsIWebNavigation)
                   .sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
                                       .createInstance(Ci.nsISHistory);
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -9,17 +9,23 @@ chrome.jar:
 % content b2g %content/
 
   content/arrow.svg                     (content/arrow.svg)
 * content/settings.js                   (content/settings.js)
 * content/shell.html                    (content/shell.html)
 * content/shell.js                      (content/shell.js)
   content/shell.css                     (content/shell.css)
   content/devtools.js                   (content/devtools.js)
-#ifndef ANDROID
+#ifdef FXOS_SIMULATOR
+  content/desktop.css                   (content/desktop.css)
+  content/images/desktop/home-black.png (content/images/desktop/home-black.png)
+  content/images/desktop/home-white.png (content/images/desktop/home-white.png)
+  content/images/desktop/rotate.png     (content/images/desktop/rotate.png)
+#endif
+#ifndef MOZ_WIDGET_GONK
   content/desktop.js                    (content/desktop.js)
   content/screen.js                     (content/screen.js)
   content/runapp.js                     (content/runapp.js)
 #endif
 * content/content.css                   (content/content.css)
   content/touchcontrols.css             (content/touchcontrols.css)
 
 * content/payment.js                    (content/payment.js)
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -76,8 +76,14 @@ category update-timer WebappsUpdateTimer
 # FxAccountsUIGlue.js
 component {51875c14-91d7-4b8c-b65d-3549e101228c} FxAccountsUIGlue.js
 contract @mozilla.org/fxaccounts/fxaccounts-ui-glue;1 {51875c14-91d7-4b8c-b65d-3549e101228c}
 #endif
 
 # HelperAppDialog.js
 component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js
 contract @mozilla.org/helperapplauncherdialog;1 {710322af-e6ae-4b0c-b2c9-1474a87b077e}
+
+#ifndef MOZ_WIDGET_GONK
+component {c83c02c0-5d43-4e3e-987f-9173b313e880} SimulatorScreen.js
+contract @mozilla.org/simulator-screen;1 {c83c02c0-5d43-4e3e-987f-9173b313e880}
+category profile-after-change SimulatorScreen @mozilla.org/simulator-screen;1
+#endif
new file mode 100644
--- /dev/null
+++ b/b2g/components/GlobalSimulatorScreen.jsm
@@ -0,0 +1,90 @@
+/* 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/. */
+
+this.EXPORTED_SYMBOLS = [ 'GlobalSimulatorScreen' ];
+
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+
+this.GlobalSimulatorScreen = {
+  mozOrientationLocked: false,
+
+  // Actual orientation of apps
+  mozOrientation: 'portrait',
+
+  // The restricted list of actual orientation that can be used
+  // if mozOrientationLocked is true
+  lockedOrientation: [],
+
+  // The faked screen orientation
+  // if screenOrientation doesn't match mozOrientation due
+  // to lockedOrientation restriction, the app will be displayed
+  // on the side on desktop
+  screenOrientation: 'portrait',
+
+  // Updated by screen.js
+  width: 0, height: 0,
+
+  lock: function(orientation) {
+    this.mozOrientationLocked = true;
+
+    // Normalize to portrait or landscape,
+    // i.e. the possible values of screenOrientation
+    function normalize(str) {
+      if (str.match(/^portrait/)) {
+        return 'portrait';
+      } else if (str.match(/^landscape/)) {
+        return 'landscape';
+      } else {
+        return 'portrait';
+      }
+    }
+    this.lockedOrientation = orientation.map(normalize);
+
+    this.updateOrientation();
+  },
+
+  unlock: function() {
+    this.mozOrientationLocked = false;
+    this.updateOrientation();
+  },
+
+  updateOrientation: function () {
+    let orientation = this.screenOrientation;
+
+    // If the orientation is locked, we have to ensure ending up with a value
+    // of lockedOrientation. If none of lockedOrientation values matches
+    // the screen orientation we just choose the first locked orientation.
+    // This will be the precise scenario where the app is displayed on the
+    // side on desktop!
+    if (this.mozOrientationLocked &&
+        this.lockedOrientation.indexOf(this.screenOrientation) == -1) {
+      orientation = this.lockedOrientation[0];
+    }
+
+    // If the actual orientation changed,
+    // we have to fire mozorientation DOM events
+    if (this.mozOrientation != orientation) {
+      this.mozOrientation = orientation;
+
+      // Notify each app screen object to fire the event
+      Services.obs.notifyObservers(null, 'simulator-orientation-change', null);
+    }
+
+    // Finally, in any case, we update the window size and orientation
+    // (Use wrappedJSObject trick to be able to pass a raw JS object)
+    Services.obs.notifyObservers({wrappedJSObject:this}, 'simulator-adjust-window-size', null);
+  },
+
+  flipScreen: function() {
+    if (this.screenOrientation == 'portrait') {
+      this.screenOrientation = 'landscape';
+    } else if (this.screenOrientation == 'landscape') {
+      this.screenOrientation = 'portrait';
+    }
+    this.updateOrientation();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/b2g/components/SimulatorScreen.js
@@ -0,0 +1,112 @@
+/* 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/. */
+
+let Ci = Components.interfaces;
+let Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+Cu.import('resource://gre/modules/DOMRequestHelper.jsm');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'GlobalSimulatorScreen',
+                                  'resource://gre/modules/GlobalSimulatorScreen.jsm');
+
+let DEBUG_PREFIX = 'SimulatorScreen.js - ';
+function debug() {
+  //dump(DEBUG_PREFIX + Array.slice(arguments) + '\n');
+}
+
+function fireOrientationEvent(window) {
+  let e = new window.Event('mozorientationchange');
+  window.screen.dispatchEvent(e);
+}
+
+function hookScreen(window) {
+  let nodePrincipal = window.document.nodePrincipal;
+  let origin = nodePrincipal.origin;
+  if (nodePrincipal.appStatus == nodePrincipal.APP_STATUS_NOT_INSTALLED) {
+    Cu.reportError('deny mozLockOrientation:' + origin + 'is not installed');
+    return;
+  }
+
+  let screen = window.wrappedJSObject.screen;
+
+  screen.mozLockOrientation = function (orientation) {
+    debug('mozLockOrientation:', orientation, 'from', origin);
+
+    // Normalize and do some checks against orientation input
+    if (typeof(orientation) == 'string') {
+      orientation = [orientation];
+    }
+
+    function isInvalidOrientationString(str) {
+      return typeof(str) != 'string' ||
+        !str.match(/^default$|^(portrait|landscape)(-(primary|secondary))?$/);
+    }
+    if (!Array.isArray(orientation) ||
+        orientation.some(isInvalidOrientationString)) {
+      Cu.reportError('Invalid orientation "' + orientation + '"');
+      return false;
+    }
+
+    GlobalSimulatorScreen.lock(orientation);
+
+    return true;
+  };
+
+  screen.mozUnlockOrientation = function() {
+    debug('mozOrientationUnlock from', origin);
+    GlobalSimulatorScreen.unlock();
+    return true;
+  };
+
+  Object.defineProperty(screen, 'width', {
+    get: function () GlobalSimulatorScreen.width
+  });
+  Object.defineProperty(screen, 'height', {
+    get: function () GlobalSimulatorScreen.height
+  });
+  Object.defineProperty(screen, 'mozOrientation', {
+    get: function () GlobalSimulatorScreen.mozOrientation
+  });
+}
+
+function SimulatorScreen() {}
+SimulatorScreen.prototype = {
+  classID:         Components.ID('{c83c02c0-5d43-4e3e-987f-9173b313e880}'),
+  QueryInterface:  XPCOMUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
+  _windows: new Set(),
+
+  observe: function (subject, topic, data) {
+    switch (topic) {
+      case 'profile-after-change':
+        Services.obs.addObserver(this, 'document-element-inserted', false);
+        Services.obs.addObserver(this, 'simulator-orientation-change', false);
+        break;
+
+      case 'document-element-inserted':
+        let window = subject.defaultView;
+        if (!window) {
+          return;
+        }
+
+        hookScreen(window);
+
+        let windows = this._windows;
+        window.addEventListener('unload', function unload() {
+          window.removeEventListener('unload', unload);
+          windows.delete(window);
+        });
+        windows.add(window);
+        break;
+
+      case 'simulator-orientation-change':
+        this._windows.forEach(fireOrientationEvent);
+        break;
+    }
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SimulatorScreen]);
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -41,16 +41,31 @@ XPCOMUtils.defineLazyServiceGetter(Servi
 XPCOMUtils.defineLazyServiceGetter(Services, "idle",
                                    "@mozilla.org/widget/idleservice;1",
                                    "nsIIdleService");
 
 XPCOMUtils.defineLazyServiceGetter(Services, "settings",
                                    "@mozilla.org/settingsService;1",
                                    "nsISettingsService");
 
+XPCOMUtils.defineLazyServiceGetter(Services, 'env',
+                                   '@mozilla.org/process/environment;1',
+                                   'nsIEnvironment');
+
+function useSettings() {
+  // When we're running in the real phone, then we can use settings.
+  // But when we're running as part of xpcshell, there is no settings database
+  // and trying to use settings in this scenario causes lots of weird
+  // assertions at shutdown time.
+  if (typeof useSettings.result === "undefined") {
+    useSettings.result = !Services.env.get("XPCSHELL_TEST_PROFILE_DIR");
+  }
+  return useSettings.result;
+}
+
 function UpdateCheckListener(updatePrompt) {
   this._updatePrompt = updatePrompt;
 }
 
 UpdateCheckListener.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateCheckListener]),
 
   _updatePrompt: null,
@@ -178,37 +193,41 @@ UpdatePrompt.prototype = {
     log("Update error, state: " + aUpdate.state + ", errorCode: " +
         aUpdate.errorCode);
     this.sendUpdateEvent("update-error", aUpdate);
     this.setUpdateStatus(aUpdate.statusText);
   },
 
   showUpdateHistory: function UP_showUpdateHistory(aParent) { },
   showUpdateInstalled: function UP_showUpdateInstalled() {
-    let lock = Services.settings.createLock();
-    lock.set("deviceinfo.last_updated", Date.now(), null, null);
+    if (useSettings()) {
+      let lock = Services.settings.createLock();
+      lock.set("deviceinfo.last_updated", Date.now(), null, null);
+    }
   },
 
   // Custom functions
 
   waitForIdle: function UP_waitForIdle() {
     if (this._waitingForIdle) {
       return;
     }
 
     this._waitingForIdle = true;
     Services.idle.addIdleObserver(this, this.applyIdleTimeout / 1000);
     Services.obs.addObserver(this, "quit-application", false);
   },
 
   setUpdateStatus: function UP_setUpdateStatus(aStatus) {
-    log("Setting gecko.updateStatus: " + aStatus);
+     if (useSettings()) {
+       log("Setting gecko.updateStatus: " + aStatus);
 
-    let lock = Services.settings.createLock();
-    lock.set("gecko.updateStatus", aStatus, null);
+       let lock = Services.settings.createLock();
+       lock.set("gecko.updateStatus", aStatus, null);
+     }
   },
 
   showApplyPrompt: function UP_showApplyPrompt(aUpdate) {
     if (!this.sendUpdateEvent("update-prompt-apply", aUpdate)) {
       log("Unable to prompt, forcing restart");
       this.restartProcess();
       return;
     }
@@ -374,30 +393,32 @@ UpdatePrompt.prototype = {
 #else
       // NB: on Gonk, we rely on the system process manager to restart us.
       let pmService = Cc["@mozilla.org/power/powermanagerservice;1"]
                       .getService(Ci.nsIPowerManagerService);
       pmService.restart();
 #endif
     }
 
-    // Save current os version in deviceinfo.previous_os
-    let lock = Services.settings.createLock({
-      handle: callbackAfterSet,
-      handleAbort: function(error) {
-        log("Abort callback when trying to set previous_os: " + error);
-        callbackAfterSet();
-      }
-    });
-    lock.get("deviceinfo.os", {
-      handle: function(name, value) {
-        log("Set previous_os to: " + value);
-        lock.set("deviceinfo.previous_os", value, null, null);
-      }
-    });
+    if (useSettings()) {
+      // Save current os version in deviceinfo.previous_os
+      let lock = Services.settings.createLock({
+        handle: callbackAfterSet,
+        handleAbort: function(error) {
+          log("Abort callback when trying to set previous_os: " + error);
+          callbackAfterSet();
+        }
+      });
+      lock.get("deviceinfo.os", {
+        handle: function(name, value) {
+          log("Set previous_os to: " + value);
+          lock.set("deviceinfo.previous_os", value, null, null);
+        }
+      });
+    }
   },
 
   forceUpdateCheck: function UP_forceUpdateCheck() {
     log("Forcing update check");
 
     let checker = Cc["@mozilla.org/updates/update-checker;1"]
                     .createInstance(Ci.nsIUpdateChecker);
     checker.checkForUpdates(this._updateCheckListener, true);
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -18,16 +18,21 @@ EXTRA_COMPONENTS += [
     'PaymentGlue.js',
     'ProcessGlobal.js',
     'SmsProtocolHandler.js',
     'TelProtocolHandler.js',
     'WebappsUpdateTimer.js',
     'YoutubeProtocolHandler.js',
 ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
+    EXTRA_COMPONENTS += [
+      'SimulatorScreen.js'
+    ]
+
 EXTRA_PP_COMPONENTS += [
     'B2GComponents.manifest',
     'DirectoryProvider.js',
     'RecoveryService.js',
 ]
 
 if CONFIG['MOZ_UPDATER']:
     EXTRA_PP_COMPONENTS += [
@@ -36,15 +41,20 @@ if CONFIG['MOZ_UPDATER']:
 
 EXTRA_JS_MODULES += [
     'ErrorPage.jsm',
     'SignInToWebsite.jsm',
     'TelURIParser.jsm',
     'WebappsUpdater.jsm',
 ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
+    EXTRA_JS_MODULES += [
+      'GlobalSimulatorScreen.jsm'
+    ]
+
 if CONFIG['MOZ_SERVICES_FXACCOUNTS']:
     EXTRA_COMPONENTS += [
         'FxAccountsUIGlue.js'
     ]
     EXTRA_JS_MODULES += [
         'FxAccountsMgmtService.jsm'
     ]
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="456499c44d1ef39b602ea02e9ed460b6aab85b44"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="15d69a6789c638709911507f74d25c0425963636">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="456499c44d1ef39b602ea02e9ed460b6aab85b44"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "remote": "", 
         "branch": "", 
         "revision": ""
     }, 
-    "revision": "91e5760ff948d3bef3959866c6a1744991560ef6", 
+    "revision": "6d2a2c5c58fce4b2263a7e5e654f6c4ccee5875a", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="15d69a6789c638709911507f74d25c0425963636">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="06d3242182370ba93db9acbe54cbe6cc8f7b239f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/configure.in
+++ b/configure.in
@@ -171,17 +171,21 @@ fi
 AC_SUBST(GAIADIR)
 if test -n "$GAIADIR" ; then
     AC_DEFINE(PACKAGE_GAIA)
 fi
 
 if test -n "$FXOS_SIMULATOR" -a -z "$GAIADIR" ; then
     AC_MSG_ERROR([FXOS_SIMULATOR=1 requires GAIADIR to be defined])
 fi
-AC_SUBST(FXOS_SIMULATOR)
+
+if test -n "$FXOS_SIMULATOR" ; then
+    AC_DEFINE(FXOS_SIMULATOR)
+    AC_SUBST(FXOS_SIMULATOR)
+fi
 
 MOZ_ARG_WITH_STRING(gonk,
 [  --with-gonk=DIR
                location of gonk dir],
     gonkdir=$withval)
 
 MOZ_ARG_WITH_STRING(gonk-toolchain-prefix,
 [  --with-gonk-toolchain-prefix=DIR
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -11,17 +11,18 @@
 #include "nsError.h"
 #include "nsIDocument.h"
 #include "nsIDOMRecordErrorEvent.h"
 #include "nsTArray.h"
 #include "DOMMediaStream.h"
 #include "EncodedBufferCache.h"
 #include "nsIDOMFile.h"
 #include "mozilla/dom/BlobEvent.h"
-
+#include "nsIPrincipal.h"
+#include "nsMimeTypes.h"
 
 #include "mozilla/dom/AudioStreamTrack.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 
 namespace mozilla {
 
 namespace dom {
 
@@ -315,17 +316,29 @@ private:
   }
 
   void AfterTracksAdded(uint8_t aTrackTypes)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     // Allocate encoder and bind with union stream.
     // At this stage, the API doesn't allow UA to choose the output mimeType format.
-    mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
+
+    nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
+    uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
+    if (doc) {
+      doc->NodePrincipal()->GetAppStatus(&appStatus);
+    }
+    // Only allow certificated application can assign AUDIO_3GPP
+    if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
+         mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP)) {
+      mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP), aTrackTypes);
+    } else {
+      mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
+    }
 
     if (!mEncoder) {
       DoSessionEndTask(NS_ERROR_ABORT);
       return;
     }
 
     // Media stream is ready but UA issues a stop method follow by start method.
     // The Session::stop would clean the mTrackUnionStream. If the AfterTracksAdded
@@ -574,31 +587,34 @@ MediaRecorder::RequestData(ErrorResult& 
 JSObject*
 MediaRecorder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return MediaRecorderBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */ already_AddRefed<MediaRecorder>
 MediaRecorder::Constructor(const GlobalObject& aGlobal,
-                           DOMMediaStream& aStream, ErrorResult& aRv)
+                           DOMMediaStream& aStream,
+                           const MediaRecorderOptions& aInitDict,
+                           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;
   }
 
   nsRefPtr<MediaRecorder> object = new MediaRecorder(aStream, ownerWindow);
+  object->SetMimeType(aInitDict.mMimeType);
   return object.forget();
 }
 
 nsresult
 MediaRecorder::CreateAndDispatchBlobEvent(already_AddRefed<nsIDOMBlob>&& aBlob)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
--- a/content/media/MediaRecorder.h
+++ b/content/media/MediaRecorder.h
@@ -15,16 +15,17 @@
 namespace mozilla {
 
 class ErrorResult;
 class DOMMediaStream;
 class EncodedBufferCache;
 class MediaEncoder;
 class ProcessedMediaStream;
 class MediaInputPort;
+struct MediaRecorderOptions;
 
 namespace dom {
 
 /**
  * Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html
  * The MediaRecorder accepts a mediaStream as input source passed from UA. When recorder starts,
  * a MediaEncoder will be created and accept the mediaStream as input source.
  * Encoder will get the raw data by track data changes, encode it by selected MIME Type, then store the encoded in EncodedBufferCache object.
@@ -70,17 +71,19 @@ public:
   DOMMediaStream* Stream() const { return mStream; }
   // The current state of the MediaRecorder object.
   RecordingState State() const { return mState; }
   // Return the current encoding MIME type selected by the MediaEncoder.
   void GetMimeType(nsString &aMimeType);
 
   static already_AddRefed<MediaRecorder>
   Constructor(const GlobalObject& aGlobal,
-              DOMMediaStream& aStream, ErrorResult& aRv);
+              DOMMediaStream& aStream,
+              const MediaRecorderOptions& aInitDict,
+              ErrorResult& aRv);
 
   // EventHandler
   IMPL_EVENT_HANDLER(dataavailable)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(stop)
   IMPL_EVENT_HANDLER(warning)
 
 protected:
--- a/content/media/encoder/MediaEncoder.cpp
+++ b/content/media/encoder/MediaEncoder.cpp
@@ -110,24 +110,32 @@ MediaEncoder::CreateEncoder(const nsAStr
     mimeType = NS_LITERAL_STRING(VIDEO_WEBM);
   }
 #endif //MOZ_WEBM_ENCODER
 #ifdef MOZ_OMX_ENCODER
   else if (MediaEncoder::IsOMXEncoderEnabled() &&
           (aMIMEType.EqualsLiteral(VIDEO_MP4) ||
           (aTrackTypes & ContainerWriter::CREATE_VIDEO_TRACK))) {
     if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK) {
-      audioEncoder = new OmxAudioTrackEncoder();
+      audioEncoder = new OmxAACAudioTrackEncoder();
       NS_ENSURE_TRUE(audioEncoder, nullptr);
     }
     videoEncoder = new OmxVideoTrackEncoder();
     writer = new ISOMediaWriter(aTrackTypes);
     NS_ENSURE_TRUE(writer, nullptr);
     NS_ENSURE_TRUE(videoEncoder, nullptr);
     mimeType = NS_LITERAL_STRING(VIDEO_MP4);
+  } else if (MediaEncoder::IsOMXEncoderEnabled() &&
+            (aMIMEType.EqualsLiteral(AUDIO_3GPP))) {
+    audioEncoder = new OmxAMRAudioTrackEncoder();
+    NS_ENSURE_TRUE(audioEncoder, nullptr);
+
+    writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3GP);
+    NS_ENSURE_TRUE(writer, nullptr);
+    mimeType = NS_LITERAL_STRING(AUDIO_3GPP);
   }
 #endif // MOZ_OMX_ENCODER
   else if (MediaDecoder::IsOggEnabled() && MediaDecoder::IsOpusEnabled() &&
            (aMIMEType.EqualsLiteral(AUDIO_OGG) ||
            (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK))) {
     writer = new OggWriter();
     audioEncoder = new OpusTrackEncoder();
     NS_ENSURE_TRUE(writer, nullptr);
--- a/content/media/encoder/OmxTrackEncoder.cpp
+++ b/content/media/encoder/OmxTrackEncoder.cpp
@@ -62,16 +62,18 @@ OmxVideoTrackEncoder::GetMetadata()
 
   if (mCanceled || mEncodingComplete) {
     return nullptr;
   }
 
   nsRefPtr<AVCTrackMetadata> meta = new AVCTrackMetadata();
   meta->mWidth = mFrameWidth;
   meta->mHeight = mFrameHeight;
+  meta->mDisplayWidth = mDisplayWidth;
+  meta->mDisplayHeight = mDisplayHeight;
   meta->mFrameRate = ENCODER_CONFIG_FRAME_RATE;
   return meta.forget();
 }
 
 nsresult
 OmxVideoTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
 {
   VideoSegment segment;
@@ -151,59 +153,16 @@ OmxVideoTrackEncoder::GetEncodedTrack(En
     mEncodingComplete = true;
     OMX_LOG("Done encoding video.");
   }
 
   return NS_OK;
 }
 
 nsresult
-OmxAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
-{
-  mChannels = aChannels;
-  mSamplingRate = aSamplingRate;
-
-  mEncoder = OMXCodecWrapper::CreateAACEncoder();
-  NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
-
-  nsresult rv = mEncoder->Configure(mChannels, mSamplingRate);
-
-  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-  mInitialized = (rv == NS_OK);
-
-  mReentrantMonitor.NotifyAll();
-
-  return NS_OK;
-}
-
-already_AddRefed<TrackMetadataBase>
-OmxAudioTrackEncoder::GetMetadata()
-{
-  {
-    // Wait if mEncoder is not initialized nor is being canceled.
-    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    while (!mCanceled && !mInitialized) {
-      mReentrantMonitor.Wait();
-    }
-  }
-
-  if (mCanceled || mEncodingComplete) {
-    return nullptr;
-  }
-
-  nsRefPtr<AACTrackMetadata> meta = new AACTrackMetadata();
-  meta->mChannels = mChannels;
-  meta->mSampleRate = mSamplingRate;
-  meta->mFrameSize = OMXCodecWrapper::kAACFrameSize;
-  meta->mFrameDuration = OMXCodecWrapper::kAACFrameDuration;
-
-  return meta.forget();
-}
-
-nsresult
 OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
 {
   nsTArray<uint8_t> frameData;
   int outFlags = 0;
   int64_t outTimeUs = -1;
 
   nsresult rv = mEncoder->GetNextEncodedFrame(&frameData, &outTimeUs, &outFlags,
                                               3000); // wait up to 3ms
@@ -213,18 +172,25 @@ OmxAudioTrackEncoder::AppendEncodedFrame
     bool isCSD = false;
     if (outFlags & OMXCodecWrapper::BUFFER_CODEC_CONFIG) { // codec specific data
       isCSD = true;
     } else if (outFlags & OMXCodecWrapper::BUFFER_EOS) { // last frame
       mEncodingComplete = true;
     }
 
     nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
-    audiodata->SetFrameType(isCSD ?
-      EncodedFrame::AAC_CSD : EncodedFrame::AAC_AUDIO_FRAME);
+    if (mEncoder->GetCodecType() == OMXCodecWrapper::AAC_ENC) {
+      audiodata->SetFrameType(isCSD ?
+        EncodedFrame::AAC_CSD : EncodedFrame::AAC_AUDIO_FRAME);
+    } else if (mEncoder->GetCodecType() == OMXCodecWrapper::AMR_NB_ENC){
+      audiodata->SetFrameType(isCSD ?
+        EncodedFrame::AMR_AUDIO_CSD : EncodedFrame::AMR_AUDIO_FRAME);
+    } else {
+      MOZ_ASSERT("audio codec not supported");
+    }
     audiodata->SetTimeStamp(outTimeUs);
     rv = audiodata->SwapInFrameData(frameData);
     NS_ENSURE_SUCCESS(rv, rv);
     aContainer.AppendEncodedFrame(audiodata);
   }
 
   return NS_OK;
 }
@@ -272,9 +238,87 @@ OmxAudioTrackEncoder::GetEncodedTrack(En
 
     rv = AppendEncodedFrames(aData);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
+nsresult
+OmxAACAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
+{
+  mChannels = aChannels;
+  mSamplingRate = aSamplingRate;
+
+  mEncoder = OMXCodecWrapper::CreateAACEncoder();
+  NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
+
+  nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, mSamplingRate);
+
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  mInitialized = (rv == NS_OK);
+
+  mReentrantMonitor.NotifyAll();
+
+  return NS_OK;
 }
+
+already_AddRefed<TrackMetadataBase>
+OmxAACAudioTrackEncoder::GetMetadata()
+{
+  {
+    // Wait if mEncoder is not initialized nor is being canceled.
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    while (!mCanceled && !mInitialized) {
+      mReentrantMonitor.Wait();
+    }
+  }
+
+  if (mCanceled || mEncodingComplete) {
+    return nullptr;
+  }
+  nsRefPtr<AACTrackMetadata> meta = new AACTrackMetadata();
+  meta->mChannels = mChannels;
+  meta->mSampleRate = mSamplingRate;
+  meta->mFrameSize = OMXCodecWrapper::kAACFrameSize;
+  meta->mFrameDuration = OMXCodecWrapper::kAACFrameDuration;
+  return meta.forget();
+}
+
+nsresult
+OmxAMRAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
+{
+  mChannels = aChannels;
+  mSamplingRate = aSamplingRate;
+
+  mEncoder = OMXCodecWrapper::CreateAMRNBEncoder();
+  NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
+
+  nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, AMR_NB_SAMPLERATE);
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  mInitialized = (rv == NS_OK);
+
+  mReentrantMonitor.NotifyAll();
+
+  return NS_OK;
+}
+
+already_AddRefed<TrackMetadataBase>
+OmxAMRAudioTrackEncoder::GetMetadata()
+{
+  {
+    // Wait if mEncoder is not initialized nor is being canceled.
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    while (!mCanceled && !mInitialized) {
+      mReentrantMonitor.Wait();
+    }
+  }
+
+  if (mCanceled || mEncodingComplete) {
+    return nullptr;
+  }
+
+  nsRefPtr<AMRTrackMetadata> meta = new AMRTrackMetadata();
+  return meta.forget();
+}
+
+}
--- a/content/media/encoder/OmxTrackEncoder.h
+++ b/content/media/encoder/OmxTrackEncoder.h
@@ -38,31 +38,59 @@ protected:
   nsresult Init(int aWidth, int aHeight,
                 int aDisplayWidth, int aDisplayHeight,
                 TrackRate aTrackRate) MOZ_OVERRIDE;
 
 private:
   nsAutoPtr<android::OMXVideoEncoder> mEncoder;
 };
 
-class OmxAudioTrackEncoder MOZ_FINAL : public AudioTrackEncoder
+class OmxAudioTrackEncoder : public AudioTrackEncoder
 {
 public:
   OmxAudioTrackEncoder()
     : AudioTrackEncoder()
   {}
 
-  already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
+  already_AddRefed<TrackMetadataBase> GetMetadata() = 0;
 
   nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_OVERRIDE;
 
 protected:
-  nsresult Init(int aChannels, int aSamplingRate) MOZ_OVERRIDE;
+  nsresult Init(int aChannels, int aSamplingRate) = 0;
 
-private:
   // Append encoded frames to aContainer.
   nsresult AppendEncodedFrames(EncodedFrameContainer& aContainer);
 
   nsAutoPtr<android::OMXAudioEncoder> mEncoder;
 };
 
+class OmxAACAudioTrackEncoder MOZ_FINAL : public OmxAudioTrackEncoder
+{
+public:
+  OmxAACAudioTrackEncoder()
+    : OmxAudioTrackEncoder()
+  {}
+
+  already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
+
+protected:
+  nsresult Init(int aChannels, int aSamplingRate) MOZ_OVERRIDE;
+};
+
+class OmxAMRAudioTrackEncoder MOZ_FINAL : public OmxAudioTrackEncoder
+{
+public:
+  OmxAMRAudioTrackEncoder()
+    : OmxAudioTrackEncoder()
+  {}
+
+  enum {
+    AMR_NB_SAMPLERATE = 8000,
+  };
+  already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
+
+protected:
+  nsresult Init(int aChannels, int aSamplingRate) MOZ_OVERRIDE;
+};
+
 }
 #endif
--- a/content/media/encoder/TrackMetadataBase.h
+++ b/content/media/encoder/TrackMetadataBase.h
@@ -44,19 +44,23 @@ public:
   virtual uint32_t GetAudioSampleRate() = 0;
 
   virtual uint32_t GetAudioChannels() = 0;
 };
 
 // The base class for video metadata.
 class VideoTrackMetadata : public TrackMetadataBase {
 public:
+  // VideoHeight and VideoWidth are the frame size of the elementary stream.
   virtual uint32_t GetVideoHeight() = 0;
+  virtual uint32_t GetVideoWidth() = 0;
 
-  virtual uint32_t GetVideoWidth() = 0;
+  // VideoDisplayHeight and VideoDisplayWidth are the display frame size.
+  virtual uint32_t GetVideoDisplayHeight() = 0;
+  virtual uint32_t GetVideoDisplayWidth() = 0;
 
   // VideoClockRate is the number of samples per second in video frame's
   // timestamp.
   // For example, if VideoClockRate is 90k Hz and VideoFrameRate is
   // 30 fps, each frame's sample duration will be 3000 Hz.
   virtual uint32_t GetVideoClockRate() = 0;
 
   // VideoFrameRate is numner of frames per second.
--- a/content/media/encoder/fmp4_muxer/ISOControl.cpp
+++ b/content/media/encoder/fmp4_muxer/ISOControl.cpp
@@ -162,28 +162,30 @@ ISOControl::GetTrackID(TrackMetadataBase
   MOZ_ASSERT(0);
   return 0;
 }
 
 nsresult
 ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta)
 {
   if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC ||
+      aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR ||
       aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC) {
     mMetaArray.AppendElement(aTrackMeta);
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
 nsresult
 ISOControl::GetAudioMetadata(nsRefPtr<AudioTrackMetadata>& aAudMeta)
 {
   for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
-    if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC) {
+    if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC ||
+        mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR) {
       aAudMeta = static_cast<AudioTrackMetadata*>(mMetaArray[i].get());
       return NS_OK;
     }
   }
   return NS_ERROR_FAILURE;
 }
 
 nsresult
--- a/content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp
+++ b/content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp
@@ -1174,18 +1174,23 @@ TrackHeaderBox::Generate(uint32_t* aBoxS
                 mControl->GetTrackID(mVideoMeta->GetKind()));
   // fragmented mp4
   duration = 0;
 
   // volume, audiotrack is always 0x0100 in 14496-12 8.3.2.2
   volume = (mTrackType == Audio_Track ? 0x0100 : 0);
 
   if (mTrackType == Video_Track) {
-    width = mVideoMeta->GetVideoWidth() << 16;
-    height = mVideoMeta->GetVideoHeight() << 16;
+    width = mVideoMeta->GetVideoDisplayWidth() << 16;
+    height = mVideoMeta->GetVideoDisplayHeight() << 16;
+    // Check display size, using the pixel size if any of them is invalid.
+    if (!width || !height) {
+      width = mVideoMeta->GetVideoWidth() << 16;
+      height = mVideoMeta->GetVideoHeight() << 16;
+    }
   }
 
   size += sizeof(creation_time) +
           sizeof(modification_time) +
           sizeof(track_ID) +
           sizeof(reserved) +
           sizeof(duration) +
           sizeof(reserved2) +
--- a/content/media/encoder/fmp4_muxer/ISOTrackMetadata.h
+++ b/content/media/encoder/fmp4_muxer/ISOTrackMetadata.h
@@ -40,33 +40,39 @@ public:
 // AVC clock rate is 90k Hz.
 #define AVC_CLOCK_RATE 90000
 
 class AVCTrackMetadata : public VideoTrackMetadata {
 public:
   // VideoTrackMetadata members
   uint32_t GetVideoHeight() MOZ_OVERRIDE { return mHeight; }
   uint32_t GetVideoWidth() MOZ_OVERRIDE {return mWidth; }
+  uint32_t GetVideoDisplayHeight() MOZ_OVERRIDE { return mDisplayHeight; }
+  uint32_t GetVideoDisplayWidth() MOZ_OVERRIDE { return mDisplayWidth;  }
   uint32_t GetVideoClockRate() MOZ_OVERRIDE { return AVC_CLOCK_RATE; }
   uint32_t GetVideoFrameRate() MOZ_OVERRIDE { return mFrameRate; }
 
   // TrackMetadataBase member
   MetadataKind GetKind() const MOZ_OVERRIDE { return METADATA_AVC; }
 
   // AVCTrackMetadata
   AVCTrackMetadata()
     : mHeight(0)
     , mWidth(0)
+    , mDisplayHeight(0)
+    , mDisplayWidth(0)
     , mFrameRate(0) {
     MOZ_COUNT_CTOR(AVCTrackMetadata);
   }
   ~AVCTrackMetadata() { MOZ_COUNT_DTOR(AVCTrackMetadata); }
 
   uint32_t mHeight;
   uint32_t mWidth;
+  uint32_t mDisplayHeight;
+  uint32_t mDisplayWidth;
   uint32_t mFrameRate;       // frames per second
 };
 
 
 // AMR sample rate is 8000 samples/s.
 #define AMR_SAMPLE_RATE 8000
 
 // Channel number is always 1.
--- a/content/media/omx/OMXCodecWrapper.cpp
+++ b/content/media/omx/OMXCodecWrapper.cpp
@@ -22,16 +22,18 @@ using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 #define ENCODER_CONFIG_BITRATE 2000000 // bps
 // How many seconds between I-frames.
 #define ENCODER_CONFIG_I_FRAME_INTERVAL 1
 // Wait up to 5ms for input buffers.
 #define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll)
+// AMR NB kbps
+#define AMRNB_BITRATE 12200
 
 #define CODEC_ERROR(args...)                                                   \
   do {                                                                         \
     __android_log_print(ANDROID_LOG_ERROR, "OMXCodecWrapper", ##args);         \
   } while (0)
 
 namespace android {
 
@@ -40,36 +42,50 @@ OMXCodecWrapper::CreateAACEncoder()
 {
   nsAutoPtr<OMXAudioEncoder> aac(new OMXAudioEncoder(CodecType::AAC_ENC));
   // Return the object only when media codec is valid.
   NS_ENSURE_TRUE(aac->IsValid(), nullptr);
 
   return aac.forget();
 }
 
+OMXAudioEncoder*
+OMXCodecWrapper::CreateAMRNBEncoder()
+{
+  nsAutoPtr<OMXAudioEncoder> amr(new OMXAudioEncoder(CodecType::AMR_NB_ENC));
+  // Return the object only when media codec is valid.
+  NS_ENSURE_TRUE(amr->IsValid(), nullptr);
+
+  return amr.forget();
+}
+
 OMXVideoEncoder*
 OMXCodecWrapper::CreateAVCEncoder()
 {
   nsAutoPtr<OMXVideoEncoder> avc(new OMXVideoEncoder(CodecType::AVC_ENC));
   // Return the object only when media codec is valid.
   NS_ENSURE_TRUE(avc->IsValid(), nullptr);
 
   return avc.forget();
 }
 
 OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType)
-  : mStarted(false)
+  : mCodecType(aCodecType)
+  , mStarted(false)
+  , mAMRCSDProvided(false)
 {
   ProcessState::self()->startThreadPool();
 
   mLooper = new ALooper();
   mLooper->start();
 
   if (aCodecType == CodecType::AVC_ENC) {
     mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_VIDEO_AVC, true);
+  } else if (aCodecType == CodecType::AMR_NB_ENC) {
+    mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AMR_NB, true);
   } else if (aCodecType == CodecType::AAC_ENC) {
     mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AAC, true);
   } else {
     NS_ERROR("Unknown codec type.");
   }
 }
 
 OMXCodecWrapper::~OMXCodecWrapper()
@@ -375,38 +391,63 @@ void OMXVideoEncoder::AppendFrame(nsTArr
     aSize & 0xFF,
   };
   aOutputBuf->SetCapacity(aSize);
   aOutputBuf->AppendElements(length, sizeof(length));
   aOutputBuf->AppendElements(aData + sizeof(length), aSize);
 }
 
 nsresult
-OMXAudioEncoder::Configure(int aChannels, int aSamplingRate)
+OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate,
+                           int aEncodedSampleRate)
 {
   MOZ_ASSERT(!mStarted);
 
-  NS_ENSURE_TRUE(aChannels > 0 && aSamplingRate > 0, NS_ERROR_INVALID_ARG);
+  NS_ENSURE_TRUE(aChannels > 0 && aInputSampleRate > 0 && aEncodedSampleRate >= 0,
+                 NS_ERROR_INVALID_ARG);
 
+  if (aInputSampleRate != aEncodedSampleRate) {
+    int error;
+    mResampler = speex_resampler_init(aChannels,
+                                      aInputSampleRate,
+                                      aEncodedSampleRate,
+                                      SPEEX_RESAMPLER_QUALITY_DEFAULT,
+                                      &error);
+
+    if (error != RESAMPLER_ERR_SUCCESS) {
+      return NS_ERROR_FAILURE;
+    }
+    speex_resampler_skip_zeros(mResampler);
+  }
   // Set up configuration parameters for AAC encoder.
   sp<AMessage> format = new AMessage;
   // Fixed values.
-  format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
-  format->setInt32("bitrate", kAACBitrate);
-  format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
+  if (mCodecType == AAC_ENC) {
+    format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
+    format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
+    format->setInt32("bitrate", kAACBitrate);
+    format->setInt32("sample-rate", aInputSampleRate);
+  } else if (mCodecType == AMR_NB_ENC) {
+    format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
+    format->setInt32("bitrate", AMRNB_BITRATE);
+    format->setInt32("sample-rate", aEncodedSampleRate);
+  } else {
+    MOZ_ASSERT(false, "Can't support this codec type!!");
+  }
   // Input values.
   format->setInt32("channel-count", aChannels);
-  format->setInt32("sample-rate", aSamplingRate);
 
   status_t result = mCodec->configure(format, nullptr, nullptr,
                                       MediaCodec::CONFIGURE_FLAG_ENCODE);
   NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
   mChannels = aChannels;
-  mSampleDuration = 1000000 / aSamplingRate;
+  mSampleDuration = 1000000 / aInputSampleRate;
+  mResamplingRatio = aEncodedSampleRate > 0 ? 1.0 *
+                      aEncodedSampleRate / aInputSampleRate : 1.0;
   result = Start();
 
   return result == OK ? NS_OK : NS_ERROR_FAILURE;
 }
 
 class InputBufferHelper MOZ_FINAL {
 public:
   InputBufferHelper(sp<MediaCodec>& aCodec, Vector<sp<ABuffer> >& aBuffers)
@@ -469,16 +510,24 @@ private:
   sp<MediaCodec>& mCodec;
   Vector<sp<ABuffer> >& mBuffers;
   size_t mIndex;
   uint8_t* mData;
   size_t mCapicity;
   size_t mOffset;
 };
 
+OMXAudioEncoder::~OMXAudioEncoder()
+{
+  if (mResampler) {
+    speex_resampler_destroy(mResampler);
+    mResampler = nullptr;
+  }
+}
+
 nsresult
 OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
 {
 #ifndef MOZ_SAMPLE_TYPE_S16
 #error MediaCodec accepts only 16-bit PCM data.
 #endif
 
   MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");
@@ -490,82 +539,97 @@ OMXAudioEncoder::Encode(AudioSegment& aS
   status_t result = buffer.Dequeue();
   if (result == -EAGAIN) {
     // All input buffers are full. Caller can try again later after consuming
     // some output buffers.
     return NS_OK;
   }
   NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
-  size_t samplesCopied = 0; // Number of copied samples.
+  size_t sourceSamplesCopied = 0; // Number of copied samples.
 
   if (numSamples > 0) {
     // Copy input PCM data to input buffer until queue is empty.
     AudioSegment::ChunkIterator iter(const_cast<AudioSegment&>(aSegment));
     while (!iter.IsEnded()) {
       AudioChunk chunk = *iter;
-      size_t samplesToCopy = chunk.GetDuration(); // Number of samples to copy.
-      size_t bytesToCopy = samplesToCopy * mChannels * sizeof(AudioDataValue);
-
+      size_t sourceSamplesToCopy = chunk.GetDuration(); // Number of samples to copy.
+      size_t bytesToCopy = sourceSamplesToCopy * mChannels *
+                           sizeof(AudioDataValue) * mResamplingRatio;
       if (bytesToCopy > buffer.AvailableSize()) {
         // Not enough space left in input buffer. Send it to encoder and get a
         // new one.
         result = buffer.Enqueue(mTimestamp, aInputFlags & ~BUFFER_EOS);
         NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
         result = buffer.Dequeue();
         if (result == -EAGAIN) {
           // All input buffers are full. Caller can try again later after
           // consuming some output buffers.
-          aSegment.RemoveLeading(samplesCopied);
+          aSegment.RemoveLeading(sourceSamplesCopied);
           return NS_OK;
         }
 
-        mTimestamp += samplesCopied * mSampleDuration;
-        samplesCopied = 0;
+        mTimestamp += sourceSamplesCopied * mSampleDuration;
+        sourceSamplesCopied = 0;
 
         NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
       }
 
       AudioDataValue* dst = reinterpret_cast<AudioDataValue*>(buffer.GetPointer());
+      uint32_t dstSamplesCopied = sourceSamplesToCopy;
       if (!chunk.IsNull()) {
-        // Append the interleaved data to input buffer.
-        AudioTrackEncoder::InterleaveTrackData(chunk, samplesToCopy, mChannels,
-                                               dst);
+        if (mResampler) {
+          nsAutoTArray<AudioDataValue, 9600> pcm;
+          pcm.SetLength(bytesToCopy);
+          // Append the interleaved data to input buffer.
+          AudioTrackEncoder::InterleaveTrackData(chunk, sourceSamplesToCopy,
+                                                 mChannels,
+                                                 pcm.Elements());
+          uint32_t inframes = sourceSamplesToCopy;
+          short* in = reinterpret_cast<short*>(pcm.Elements());
+          speex_resampler_process_interleaved_int(mResampler, in, &inframes,
+                                                              dst, &dstSamplesCopied);
+        } else {
+          AudioTrackEncoder::InterleaveTrackData(chunk, sourceSamplesToCopy,
+                                                 mChannels,
+                                                 dst);
+          dstSamplesCopied = sourceSamplesToCopy * mChannels;
+        }
       } else {
         // Silence.
-        memset(dst, 0, bytesToCopy);
+        memset(dst, 0, mResamplingRatio * sourceSamplesToCopy * sizeof(AudioDataValue));
       }
 
-      samplesCopied += samplesToCopy;
-      buffer.IncreaseOffset(bytesToCopy);
+      sourceSamplesCopied += sourceSamplesToCopy;
+      buffer.IncreaseOffset(dstSamplesCopied * sizeof(AudioDataValue));
       iter.Next();
     }
-    if (samplesCopied > 0) {
-      aSegment.RemoveLeading(samplesCopied);
+    if (sourceSamplesCopied > 0) {
+      aSegment.RemoveLeading(sourceSamplesCopied);
     }
   } else if (aInputFlags & BUFFER_EOS) {
     // No audio data left in segment but we still have to feed something to
     // MediaCodec in order to notify EOS.
     size_t bytesToCopy = mChannels * sizeof(AudioDataValue);
     memset(buffer.GetPointer(), 0, bytesToCopy);
     buffer.IncreaseOffset(bytesToCopy);
-    samplesCopied = 1;
+    sourceSamplesCopied = 1;
   }
 
-  if (samplesCopied > 0) {
+  if (sourceSamplesCopied > 0) {
     int flags = aInputFlags;
     if (aSegment.GetDuration() > 0) {
       // Don't signal EOS until source segment is empty.
       flags &= ~BUFFER_EOS;
     }
     result = buffer.Enqueue(mTimestamp, flags);
     NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
-    mTimestamp += samplesCopied * mSampleDuration;
+    mTimestamp += sourceSamplesCopied * mSampleDuration;
   }
 
   return NS_OK;
 }
 
 // Generate decoder config descriptor (defined in ISO/IEC 14496-1 8.3.4.1) for
 // AAC. The hard-coded bytes are copied from
 // MPEG4Writer::Track::writeMp4aEsdsBox() implementation in libstagefright.
@@ -658,16 +722,30 @@ OMXCodecWrapper::GetNextEncodedFrame(nsT
     aOutputBuf->Clear();
     const sp<ABuffer> omxBuf = mOutputBufs.itemAt(index);
     if (outFlags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
       // Codec specific data.
       if (AppendDecoderConfig(aOutputBuf, omxBuf.get()) != OK) {
         mCodec->releaseOutputBuffer(index);
         return NS_ERROR_FAILURE;
       }
+    } else if ((mCodecType == AMR_NB_ENC) && !mAMRCSDProvided){
+      // OMX AMR codec won't provide csd data, need to generate a fake one.
+      nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
+      // Decoder config descriptor
+      const uint8_t decConfig[] = {
+        0x0, 0x0, 0x0, 0x0, // vendor: 4 bytes
+        0x0,                // decoder version
+        0x83, 0xFF,         // mode set: all enabled
+        0x00,               // mode change period
+        0x01,               // frames per sample
+      };
+      aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
+      outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
+      mAMRCSDProvided = true;
     } else {
       AppendFrame(aOutputBuf, omxBuf->data(), omxBuf->size());
     }
   }
   mCodec->releaseOutputBuffer(index);
 
   if (aOutputTimestamp) {
     *aOutputTimestamp = outTimeUs;
--- a/content/media/omx/OMXCodecWrapper.h
+++ b/content/media/omx/OMXCodecWrapper.h
@@ -10,16 +10,18 @@
 #include <stagefright/foundation/ABuffer.h>
 #include <stagefright/foundation/AMessage.h>
 #include <stagefright/MediaCodec.h>
 
 #include "AudioSegment.h"
 #include "GonkNativeWindow.h"
 #include "GonkNativeWindowClient.h"
 
+#include <speex/speex_resampler.h>
+
 namespace android {
 
 class OMXAudioEncoder;
 class OMXVideoEncoder;
 
 /**
  * This class (and its subclasses) wraps the video and audio codec from
  * MediaCodec API in libstagefright. Currently only AVC/H.264 video encoder and
@@ -48,16 +50,17 @@ class OMXVideoEncoder;
  * fail.
  */
 class OMXCodecWrapper
 {
 public:
   // Codec types.
   enum CodecType {
     AAC_ENC, // AAC encoder.
+    AMR_NB_ENC, // AMR_NB encoder.
     AVC_ENC, // AVC/H.264 encoder.
     TYPE_COUNT
   };
 
   // Input and output flags.
   enum {
     // For Encode() and Encode, it indicates the end of input stream;
     // For GetNextEncodedFrame(), it indicates the end of output
@@ -78,31 +81,37 @@ public:
     kAACBitrate = 96000,      // kbps
     kAACFrameSize = 768,      // bytes
     kAACFrameDuration = 1024, // How many samples per AAC frame.
   };
 
   /** Create a AAC audio encoder. Returns nullptr when failed. */
   static OMXAudioEncoder* CreateAACEncoder();
 
+  /** Create a AMR audio encoder. Returns nullptr when failed. */
+  static OMXAudioEncoder* CreateAMRNBEncoder();
+
   /** Create a AVC/H.264 video encoder. Returns nullptr when failed. */
   static OMXVideoEncoder* CreateAVCEncoder();
 
   virtual ~OMXCodecWrapper();
 
   /**
    * Get the next available encoded data from MediaCodec. The data will be
    * copied into aOutputBuf array, with its timestamp (in microseconds) in
    * aOutputTimestamp.
    * Wait at most aTimeout microseconds to dequeue a output buffer.
    */
   nsresult GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
                                int64_t* aOutputTimestamp, int* aOutputFlags,
                                int64_t aTimeOut);
-
+  /*
+   * Get the codec type
+   */
+  int GetCodecType() { return mCodecType; }
 protected:
   /**
    * See whether the object has been initialized successfully and is ready to
    * use.
    */
   virtual bool IsValid() { return mCodec != nullptr; }
 
   /**
@@ -155,64 +164,76 @@ private:
   sp<MediaCodec> mCodec;
 
   // A dedicate message loop with its own thread used by MediaCodec.
   sp<ALooper> mLooper;
 
   Vector<sp<ABuffer> > mInputBufs;  // MediaCodec buffers to hold input data.
   Vector<sp<ABuffer> > mOutputBufs; // MediaCodec buffers to hold output data.
 
+  int mCodecType;
   bool mStarted; // Has MediaCodec been started?
+  bool mAMRCSDProvided;
 };
 
 /**
  * Audio encoder.
  */
 class OMXAudioEncoder MOZ_FINAL : public OMXCodecWrapper
 {
 public:
   /**
    * Configure audio codec parameters and start media codec. It must be called
    * before calling Encode() and GetNextEncodedFrame().
+   * aReSamplingRate = 0 means no resampler required
    */
-  nsresult Configure(int aChannelCount, int aSampleRate);
+  nsresult Configure(int aChannelCount, int aInputSampleRate, int aEncodedSampleRate);
 
   /**
    * Encode 16-bit PCM audio samples stored in aSegment. To notify end of
    * stream, set aInputFlags to BUFFER_EOS. Since encoder has limited buffers,
    * this function might not be able to encode all chunks in one call, however
    * it will remove chunks it consumes from aSegment.
    */
   nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0);
 
+  ~OMXAudioEncoder();
 protected:
   virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
                                        ABuffer* aData) MOZ_OVERRIDE;
-
 private:
   // Hide these. User should always use creator functions to get a media codec.
   OMXAudioEncoder() MOZ_DELETE;
   OMXAudioEncoder(const OMXAudioEncoder&) MOZ_DELETE;
   OMXAudioEncoder& operator=(const OMXAudioEncoder&) MOZ_DELETE;
 
   /**
    * Create a audio codec. It will be a AAC encoder if aCodecType is
    * CODEC_AAC_ENC.
    */
   OMXAudioEncoder(CodecType aCodecType)
     : OMXCodecWrapper(aCodecType)
+    , mResampler(nullptr)
     , mChannels(0)
     , mTimestamp(0)
-    , mSampleDuration(0) {}
+    , mSampleDuration(0)
+    , mResamplingRatio(0) {}
 
   // For creator function to access hidden constructor.
   friend class OMXCodecWrapper;
 
+  /**
+   * If the input sample rate does not divide 48kHz evenly, the input data are
+   * resampled.
+   */
+  SpeexResamplerState* mResampler;
   // Number of audio channels.
   size_t mChannels;
+
+  float mResamplingRatio;
   // The total duration of audio samples that have been encoded in microseconds.
   int64_t mTimestamp;
   // Time per audio sample in microseconds.
   int64_t mSampleDuration;
 };
 
 /**
  * Video encoder.
--- a/content/media/test/test_new_audio.html
+++ b/content/media/test/test_new_audio.html
@@ -25,22 +25,20 @@ var manager = new MediaTestManager;
 var player = new Audio();
 
 function startTest(test, token) {
   if (!player.canPlayType(test.type)) {
     return;
   }
   manager.started(token);
   var a = new Audio(test.name);
-  a.addEventListener("canplaythrough",
-                     function(e){ e.target.play(); },
-                      false);
+  a.autoplay = true;
   a.addEventListener("ended",
                      function(e){
-                        ok(true, "We should get to the end. Oh look we did.");
+                        ok(true, "[" + a.src + "]We should get to the end. Oh look we did.");
                         manager.finished(token);
                      },
                      false);
 }
 
 manager.runTests(gAudioTests, startTest);
 
 </script>
--- a/dom/browser-element/mochitest/priority/test_Preallocated.html
+++ b/dom/browser-element/mochitest/priority/test_Preallocated.html
@@ -56,17 +56,17 @@ function runTest()
               "false for this test to work.");
     SimpleTest.finish();
     return;
   }
 
   // Ensure that the preallocated process initially gets BACKGROUND priority.
   // That's it.
   expectProcessCreated().then(function(childID) {
-    return expectPriorityChange(childID, 'BACKGROUND');
+    return expectPriorityChange(childID, 'PREALLOC');
   }).then(function() {
     cleanUp();
     SimpleTest.finish();
   });
 
   // Setting this pref to true should cause us to prelaunch a process.
   SpecialPowers.setBoolPref('dom.ipc.processPrelaunch.enabled', true);
 }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -443,17 +443,17 @@ ContentParent::RunNuwaProcess()
 // MaybeTakePreallocatedAppProcess.
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::PreallocateAppProcess()
 {
     nsRefPtr<ContentParent> process =
         new ContentParent(/* app = */ nullptr,
                           /* isForBrowserElement = */ false,
                           /* isForPreallocated = */ true,
-                          PROCESS_PRIORITY_BACKGROUND);
+                          PROCESS_PRIORITY_PREALLOC);
     process->Init();
     return process.forget();
 }
 
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::MaybeTakePreallocatedAppProcess(const nsAString& aAppManifestURL,
                                                ProcessPriority aInitialPriority)
 {
@@ -1448,17 +1448,17 @@ ContentParent::ContentParent(ContentPare
     Open(mSubprocess->GetChannel(),
          mSubprocess->GetChildProcessHandle());
 
     // Set the subprocess's priority (bg if we're a preallocated process, fg
     // otherwise).  We do this first because we're likely /lowering/ its CPU and
     // memory priority, which it has inherited from this process.
     ProcessPriority priority;
     if (IsPreallocated()) {
-        priority = PROCESS_PRIORITY_BACKGROUND;
+        priority = PROCESS_PRIORITY_PREALLOC;
     } else {
         priority = PROCESS_PRIORITY_FOREGROUND;
     }
 
     InitInternal(priority,
                  false, /* Setup Off-main thread compositing */
                  false  /* Send registered chrome */);
 }
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -940,16 +940,20 @@ ParticularProcessPriorityManager::Comput
   return HasAppType("homescreen") ?
          PROCESS_PRIORITY_BACKGROUND_HOMESCREEN :
          PROCESS_PRIORITY_BACKGROUND;
 }
 
 ProcessCPUPriority
 ParticularProcessPriorityManager::ComputeCPUPriority()
 {
+  if (mPriority == PROCESS_PRIORITY_PREALLOC) {
+    return PROCESS_CPU_PRIORITY_LOW;
+  }
+
   if (mPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH) {
     return PROCESS_CPU_PRIORITY_NORMAL;
   }
 
   return ProcessPriorityManagerImpl::GetSingleton()->
     OtherProcessHasHighPriority(this) ?
     PROCESS_CPU_PRIORITY_LOW :
     PROCESS_CPU_PRIORITY_NORMAL;
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -331,17 +331,19 @@ MediaElementChecker.prototype = {
  */
 function isNetworkReady() {
   // for gonk platform
   if ("nsINetworkInterfaceListService" in SpecialPowers.Ci) {
     var listService = SpecialPowers.Cc["@mozilla.org/network/interface-list-service;1"]
                         .getService(SpecialPowers.Ci.nsINetworkInterfaceListService);
     var itfList = listService.getDataInterfaceList(
           SpecialPowers.Ci.nsINetworkInterfaceListService.LIST_NOT_INCLUDE_MMS_INTERFACES |
-          SpecialPowers.Ci.nsINetworkInterfaceListService.LIST_NOT_INCLUDE_SUPL_INTERFACES);
+          SpecialPowers.Ci.nsINetworkInterfaceListService.LIST_NOT_INCLUDE_SUPL_INTERFACES |
+          SpecialPowers.Ci.nsINetworkInterfaceListService.LIST_NOT_INCLUDE_IMS_INTERFACES |
+          SpecialPowers.Ci.nsINetworkInterfaceListService.LIST_NOT_INCLUDE_DUN_INTERFACES);
     var num = itfList.getNumberOfInterface();
     for (var i = 0; i < num; i++) {
       if (itfList.getInterface(i).ip) {
         info("Network interface is ready with address: " + itfList.getInterface(i).ip);
         return true;
       }
     }
     // ip address is not available
--- a/dom/mobilemessage/interfaces/nsIMobileMessageService.idl
+++ b/dom/mobilemessage/interfaces/nsIMobileMessageService.idl
@@ -9,56 +9,56 @@ interface nsIDOMMozMmsMessage;
 interface nsIDOMMozMobileMessageThread;
 interface nsIDOMMozSmsSegmentInfo;
 
 %{C++
 #define MOBILE_MESSAGE_SERVICE_CID { 0x829c1dd6, 0x0466, 0x4591, { 0x83, 0x6f, 0xb8, 0xf6, 0xfd, 0x1f, 0x7b, 0xa5 } }
 #define MOBILE_MESSAGE_SERVICE_CONTRACTID "@mozilla.org/mobilemessage/mobilemessageservice;1"
 %}
 
-[scriptable, builtinclass, uuid(67d038b2-0039-11e3-9fd3-83de190730f7)]
+[scriptable, builtinclass, uuid(17fce9e4-af56-11e3-83d9-b71055e95493)]
 interface nsIMobileMessageService : nsISupports
 {
   [implicit_jscontext]
-  nsIDOMMozSmsMessage createSmsMessage(in long      id,
+  nsIDOMMozSmsMessage createSmsMessage(in long               id,
                                        in unsigned long long threadId,
-                                       in DOMString iccId,
-                                       in DOMString delivery,
-                                       in DOMString deliveryStatus,
-                                       in DOMString sender,
-                                       in DOMString receiver,
-                                       in DOMString body,
-                                       in DOMString messageClass,
-                                       in jsval     timestamp,
-                                       in jsval     sentTimestamp,
-                                       in jsval     deliveryTimestamp,
-                                       in bool      read);
+                                       in DOMString          iccId,
+                                       in DOMString          delivery,
+                                       in DOMString          deliveryStatus,
+                                       in DOMString          sender,
+                                       in DOMString          receiver,
+                                       in DOMString          body,
+                                       in DOMString          messageClass,
+                                       in unsigned long long timestamp,
+                                       in unsigned long long sentTimestamp,
+                                       in unsigned long long deliveryTimestamp,
+                                       in bool               read);
 
   [implicit_jscontext]
-  nsIDOMMozMmsMessage createMmsMessage(in long      id,
+  nsIDOMMozMmsMessage createMmsMessage(in long               id,
                                        in unsigned long long threadId,
-                                       in DOMString iccId,
-                                       in DOMString delivery,
-                                       in jsval     deliveryInfo,
-                                       in DOMString sender,
-                                       in jsval     receivers,
-                                       in jsval     timestamp,
-                                       in jsval     sentTimestamp,
-                                       in boolean   read,
-                                       in DOMString subject,
-                                       in DOMString smil,
-                                       in jsval     attachments,
-                                       in jsval     expiryDate,
-                                       in boolean   readReportRequested);
+                                       in DOMString          iccId,
+                                       in DOMString          delivery,
+                                       in jsval              deliveryInfo,
+                                       in DOMString          sender,
+                                       in jsval              receivers,
+                                       in unsigned long long timestamp,
+                                       in unsigned long long sentTimestamp,
+                                       in boolean            read,
+                                       in DOMString          subject,
+                                       in DOMString          smil,
+                                       in jsval              attachments,
+                                       in unsigned long long expiryDate,
+                                       in boolean            readReportRequested);
 
   nsIDOMMozSmsSegmentInfo createSmsSegmentInfo(in long segments,
                                                in long charsPerSegment,
                                                in long charsAvailableInLastSegment);
 
   [implicit_jscontext]
   nsIDOMMozMobileMessageThread createThread(in unsigned long long id,
                                             in jsval              participants,
-                                            in jsval              timestamp,
+                                            in unsigned long long timestamp,
                                             in DOMString          lastMessageSubject,
                                             in DOMString          body,
                                             in unsigned long long unreadCount,
                                             in DOMString          aLastMessageType);
 };
deleted file mode 100644
--- a/dom/mobilemessage/src/MessageUtils.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: C++; 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/. */
-
-#ifndef MessageUtils_h
-#define MessageUtils_h
-
-/**
- * A helper function to convert the JS value to an integer value for time.
- *
- * @params aCx
- *         The JS context.
- * @params aTime
- *         Can be an object or a number.
- * @params aReturn
- *         The integer value to return.
- * @return NS_OK if the convertion succeeds.
- */
-static nsresult
-convertTimeToInt(JSContext* aCx, const JS::Value& aTime, uint64_t& aReturn)
-{
-  if (aTime.isObject()) {
-    JS::Rooted<JSObject*> timestampObj(aCx, &aTime.toObject());
-    if (!JS_ObjectIsDate(aCx, timestampObj)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    aReturn = js_DateGetMsecSinceEpoch(timestampObj);
-  } else {
-    if (!aTime.isNumber()) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    double number = aTime.toNumber();
-    if (static_cast<uint64_t>(number) != number) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    aReturn = static_cast<uint64_t>(number);
-  }
-  return NS_OK;
-}
-
-#endif
--- a/dom/mobilemessage/src/MmsMessage.cpp
+++ b/dom/mobilemessage/src/MmsMessage.cpp
@@ -11,17 +11,16 @@
 #include "nsContentUtils.h"
 #include "nsIDOMFile.h"
 #include "nsTArrayHelpers.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
 #include "mozilla/dom/mobilemessage/SmsTypes.h"
 #include "nsDOMFile.h"
 #include "nsCxPusher.h"
-#include "MessageUtils.h"
 
 using namespace mozilla::dom::mobilemessage;
 
 DOMCI_DATA(MozMmsMessage, mozilla::dom::MmsMessage)
 
 namespace mozilla {
 namespace dom {
 
@@ -162,32 +161,32 @@ MmsMessage::MmsMessage(const mobilemessa
     // Prepare |info.mReadTimestamp|.
     info.mReadTimestamp = infoData.readTimestamp();
 
     mDeliveryInfo.AppendElement(info);
   }
 }
 
 /* static */ nsresult
-MmsMessage::Create(int32_t               aId,
-                   uint64_t              aThreadId,
-                   const nsAString&      aIccId,
-                   const nsAString&      aDelivery,
-                   const JS::Value&      aDeliveryInfo,
-                   const nsAString&      aSender,
-                   const JS::Value&      aReceivers,
-                   const JS::Value&      aTimestamp,
-                   const JS::Value&      aSentTimestamp,
-                   bool                  aRead,
-                   const nsAString&      aSubject,
-                   const nsAString&      aSmil,
-                   const JS::Value&      aAttachments,
-                   const JS::Value&      aExpiryDate,
-                   bool                  aIsReadReportRequested,
-                   JSContext*            aCx,
+MmsMessage::Create(int32_t aId,
+                   uint64_t aThreadId,
+                   const nsAString& aIccId,
+                   const nsAString& aDelivery,
+                   const JS::Value& aDeliveryInfo,
+                   const nsAString& aSender,
+                   const JS::Value& aReceivers,
+                   uint64_t aTimestamp,
+                   uint64_t aSentTimestamp,
+                   bool aRead,
+                   const nsAString& aSubject,
+                   const nsAString& aSmil,
+                   const JS::Value& aAttachments,
+                   uint64_t aExpiryDate,
+                   bool aIsReadReportRequested,
+                   JSContext* aCx,
                    nsIDOMMozMmsMessage** aMessage)
 {
   *aMessage = nullptr;
 
   // Set |delivery|.
   DeliveryState delivery;
   if (aDelivery.Equals(DELIVERY_SENT)) {
     delivery = eDeliveryState_Sent;
@@ -250,26 +249,16 @@ MmsMessage::Create(int32_t              
       return NS_ERROR_INVALID_ARG;
     }
 
     nsDependentJSString receiverStr;
     receiverStr.init(aCx, receiverJsVal.toString());
     receivers.AppendElement(receiverStr);
   }
 
-  // Set |timestamp|.
-  uint64_t timestamp;
-  nsresult rv = convertTimeToInt(aCx, aTimestamp, timestamp);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Set |sentTimestamp|.
-  uint64_t sentTimestamp;
-  rv = convertTimeToInt(aCx, aSentTimestamp, sentTimestamp);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // Set |attachments|.
   if (!aAttachments.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
   JS::Rooted<JSObject*> attachmentsObj(aCx, &aAttachments.toObject());
   if (!JS_IsArrayObject(aCx, attachmentsObj)) {
     return NS_ERROR_INVALID_ARG;
   }
@@ -286,35 +275,30 @@ MmsMessage::Create(int32_t              
     MmsAttachment attachment;
     if (!attachment.Init(aCx, attachmentJsVal)) {
       return NS_ERROR_TYPE_ERR;
     }
 
     attachments.AppendElement(attachment);
   }
 
-  // Set |expiryDate|.
-  uint64_t expiryDate;
-  rv = convertTimeToInt(aCx, aExpiryDate, expiryDate);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsCOMPtr<nsIDOMMozMmsMessage> message = new MmsMessage(aId,
                                                          aThreadId,
                                                          aIccId,
                                                          delivery,
                                                          deliveryInfo,
                                                          aSender,
                                                          receivers,
-                                                         timestamp,
-                                                         sentTimestamp,
+                                                         aTimestamp,
+                                                         aSentTimestamp,
                                                          aRead,
                                                          aSubject,
                                                          aSmil,
                                                          attachments,
-                                                         expiryDate,
+                                                         aExpiryDate,
                                                          aIsReadReportRequested);
   message.forget(aMessage);
   return NS_OK;
 }
 
 bool
 MmsMessage::GetData(ContentParent* aParent,
                     mobilemessage::MmsMessageData& aData)
--- a/dom/mobilemessage/src/MmsMessage.h
+++ b/dom/mobilemessage/src/MmsMessage.h
@@ -36,70 +36,70 @@ public:
 
     explicit Attachment(const MmsAttachment& aAttachment) :
       content(aAttachment.mContent),
       id(aAttachment.mId),
       location(aAttachment.mLocation)
     {}
   };
 
-  MmsMessage(int32_t                               aId,
-             uint64_t                              aThreadId,
-             const nsAString&                      aIccId,
-             mobilemessage::DeliveryState          aDelivery,
-             const nsTArray<MmsDeliveryInfo>&      aDeliveryInfo,
-             const nsAString&                      aSender,
-             const nsTArray<nsString>&             aReceivers,
-             uint64_t                              aTimestamp,
-             uint64_t                              aSentTimestamp,
-             bool                                  aRead,
-             const nsAString&                      aSubject,
-             const nsAString&                      aSmil,
-             const nsTArray<Attachment>&           aAttachments,
-             uint64_t                              aExpiryDate,
-             bool                                  aReadReportRequested);
+  MmsMessage(int32_t aId,
+             uint64_t aThreadId,
+             const nsAString& aIccId,
+             mobilemessage::DeliveryState aDelivery,
+             const nsTArray<MmsDeliveryInfo>& aDeliveryInfo,
+             const nsAString& aSender,
+             const nsTArray<nsString>& aReceivers,
+             uint64_t aTimestamp,
+             uint64_t aSentTimestamp,
+             bool aRead,
+             const nsAString& aSubject,
+             const nsAString& aSmil,
+             const nsTArray<Attachment>& aAttachments,
+             uint64_t aExpiryDate,
+             bool aReadReportRequested);
 
   MmsMessage(const mobilemessage::MmsMessageData& aData);
 
-  static nsresult Create(int32_t               aId,
-                         uint64_t              aThreadId,
-                         const nsAString&      aIccId,
-                         const nsAString&      aDelivery,
-                         const JS::Value&      aDeliveryInfo,
-                         const nsAString&      aSender,
-                         const JS::Value&      aReceivers,
-                         const JS::Value&      aTimestamp,
-                         const JS::Value&      aSentTimestamp,
-                         bool                  aRead,
-                         const nsAString&      aSubject,
-                         const nsAString&      aSmil,
-                         const JS::Value&      aAttachments,
-                         const JS::Value&      aExpiryDate,
-                         bool                  aReadReportRequested,
-                         JSContext*            aCx,
+  static nsresult Create(int32_t aId,
+                         uint64_t aThreadId,
+                         const nsAString& aIccId,
+                         const nsAString& aDelivery,
+                         const JS::Value& aDeliveryInfo,
+                         const nsAString& aSender,
+                         const JS::Value& aReceivers,
+                         uint64_t aTimestamp,
+                         uint64_t aSentTimestamp,
+                         bool aRead,
+                         const nsAString& aSubject,
+                         const nsAString& aSmil,
+                         const JS::Value& aAttachments,
+                         uint64_t aExpiryDate,
+                         bool aReadReportRequested,
+                         JSContext* aCx,
                          nsIDOMMozMmsMessage** aMessage);
 
   bool GetData(ContentParent* aParent,
                mobilemessage::MmsMessageData& aData);
 
 private:
 
-  int32_t                        mId;
-  uint64_t                       mThreadId;
-  nsString                       mIccId;
-  mobilemessage::DeliveryState   mDelivery;
-  nsTArray<MmsDeliveryInfo>      mDeliveryInfo;
-  nsString                       mSender;
-  nsTArray<nsString>             mReceivers;
-  uint64_t                       mTimestamp;
-  uint64_t                       mSentTimestamp;
-  bool                           mRead;
-  nsString                       mSubject;
-  nsString                       mSmil;
-  nsTArray<Attachment>           mAttachments;
-  uint64_t                       mExpiryDate;
-  bool                           mReadReportRequested;
+  int32_t mId;
+  uint64_t mThreadId;
+  nsString mIccId;
+  mobilemessage::DeliveryState mDelivery;
+  nsTArray<MmsDeliveryInfo> mDeliveryInfo;
+  nsString mSender;
+  nsTArray<nsString> mReceivers;
+  uint64_t mTimestamp;
+  uint64_t mSentTimestamp;
+  bool mRead;
+  nsString mSubject;
+  nsString mSmil;
+  nsTArray<Attachment> mAttachments;
+  uint64_t mExpiryDate;
+  bool mReadReportRequested;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobilemessage_MmsMessage_h
--- a/dom/mobilemessage/src/MobileMessageService.cpp
+++ b/dom/mobilemessage/src/MobileMessageService.cpp
@@ -33,20 +33,20 @@ MobileMessageService::CreateSmsMessage(i
                                        uint64_t aThreadId,
                                        const nsAString& aIccId,
                                        const nsAString& aDelivery,
                                        const nsAString& aDeliveryStatus,
                                        const nsAString& aSender,
                                        const nsAString& aReceiver,
                                        const nsAString& aBody,
                                        const nsAString& aMessageClass,
-                                       JS::Handle<JS::Value> aTimestamp,
-                                       JS::Handle<JS::Value> aSentTimestamp,
-                                       JS::Handle<JS::Value> aDeliveryTimestamp,
-                                       const bool aRead,
+                                       uint64_t aTimestamp,
+                                       uint64_t aSentTimestamp,
+                                       uint64_t aDeliveryTimestamp,
+                                       bool aRead,
                                        JSContext* aCx,
                                        nsIDOMMozSmsMessage** aMessage)
 {
   return SmsMessage::Create(aId,
                             aThreadId,
                             aIccId,
                             aDelivery,
                             aDeliveryStatus,
@@ -58,32 +58,32 @@ MobileMessageService::CreateSmsMessage(i
                             aSentTimestamp,
                             aDeliveryTimestamp,
                             aRead,
                             aCx,
                             aMessage);
 }
 
 NS_IMETHODIMP
-MobileMessageService::CreateMmsMessage(int32_t               aId,
-                                       uint64_t              aThreadId,
-                                       const nsAString&      aIccId,
-                                       const nsAString&      aDelivery,
+MobileMessageService::CreateMmsMessage(int32_t aId,
+                                       uint64_t aThreadId,
+                                       const nsAString& aIccId,
+                                       const nsAString& aDelivery,
                                        JS::Handle<JS::Value> aDeliveryInfo,
-                                       const nsAString&      aSender,
+                                       const nsAString& aSender,
                                        JS::Handle<JS::Value> aReceivers,
-                                       JS::Handle<JS::Value> aTimestamp,
-                                       JS::Handle<JS::Value> aSentTimestamp,
-                                       bool                  aRead,
-                                       const nsAString&      aSubject,
-                                       const nsAString&      aSmil,
+                                       uint64_t aTimestamp,
+                                       uint64_t aSentTimestamp,
+                                       bool aRead,
+                                       const nsAString& aSubject,
+                                       const nsAString& aSmil,
                                        JS::Handle<JS::Value> aAttachments,
-                                       JS::Handle<JS::Value> aExpiryDate,
-                                       bool                  aReadReportRequested,
-                                       JSContext*            aCx,
+                                       uint64_t aExpiryDate,
+                                       bool aReadReportRequested,
+                                       JSContext* aCx,
                                        nsIDOMMozMmsMessage** aMessage)
 {
   return MmsMessage::Create(aId,
                             aThreadId,
                             aIccId,
                             aDelivery,
                             aDeliveryInfo,
                             aSender,
@@ -110,17 +110,17 @@ MobileMessageService::CreateSmsSegmentIn
       new SmsSegmentInfo(aSegments, aCharsPerSegment, aCharsAvailableInLastSegment);
   info.forget(aSegmentInfo);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileMessageService::CreateThread(uint64_t aId,
                                    JS::Handle<JS::Value> aParticipants,
-                                   JS::Handle<JS::Value> aTimestamp,
+                                   uint64_t aTimestamp,
                                    const nsAString& aLastMessageSubject,
                                    const nsAString& aBody,
                                    uint64_t aUnreadCount,
                                    const nsAString& aLastMessageType,
                                    JSContext* aCx,
                                    nsIDOMMozMobileMessageThread** aThread)
 {
   return MobileMessageThread::Create(aId,
--- a/dom/mobilemessage/src/MobileMessageThread.cpp
+++ b/dom/mobilemessage/src/MobileMessageThread.cpp
@@ -23,22 +23,22 @@ NS_INTERFACE_MAP_BEGIN(MobileMessageThre
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozMobileMessageThread)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(MobileMessageThread)
 NS_IMPL_RELEASE(MobileMessageThread)
 
 /* static */ nsresult
-MobileMessageThread::Create(const uint64_t aId,
+MobileMessageThread::Create(uint64_t aId,
                             const JS::Value& aParticipants,
-                            const JS::Value& aTimestamp,
+                            uint64_t aTimestamp,
                             const nsAString& aLastMessageSubject,
                             const nsAString& aBody,
-                            const uint64_t aUnreadCount,
+                            uint64_t aUnreadCount,
                             const nsAString& aLastMessageType,
                             JSContext* aCx,
                             nsIDOMMozMobileMessageThread** aThread)
 {
   *aThread = nullptr;
 
   // ThreadData exposes these as references, so we can simply assign
   // to them.
@@ -71,35 +71,20 @@ MobileMessageThread::Create(const uint64
       }
 
       nsDependentJSString str;
       str.init(aCx, val.toString());
       data.participants().AppendElement(str);
     }
   }
 
-  // We support both a Date object and a millisecond timestamp as a number.
-  if (aTimestamp.isObject()) {
-    JS::Rooted<JSObject*> obj(aCx, &aTimestamp.toObject());
-    if (!JS_ObjectIsDate(aCx, obj)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    data.timestamp() = js_DateGetMsecSinceEpoch(obj);
-  } else {
-    if (!aTimestamp.isNumber()) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    double number = aTimestamp.toNumber();
-    if (static_cast<uint64_t>(number) != number) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    data.timestamp() = static_cast<uint64_t>(number);
-  }
+  // Set |timestamp|;
+  data.timestamp() = aTimestamp;
 
-  // Set |aLastMessageType|.
+  // Set |lastMessageType|.
   {
     MessageType lastMessageType;
     if (aLastMessageType.Equals(MESSAGE_TYPE_SMS)) {
       lastMessageType = eMessageType_SMS;
     } else if (aLastMessageType.Equals(MESSAGE_TYPE_MMS)) {
       lastMessageType = eMessageType_MMS;
     } else {
       return NS_ERROR_INVALID_ARG;
@@ -107,22 +92,22 @@ MobileMessageThread::Create(const uint64
     data.lastMessageType() = lastMessageType;
   }
 
   nsCOMPtr<nsIDOMMozMobileMessageThread> thread = new MobileMessageThread(data);
   thread.forget(aThread);
   return NS_OK;
 }
 
-MobileMessageThread::MobileMessageThread(const uint64_t aId,
+MobileMessageThread::MobileMessageThread(uint64_t aId,
                                          const nsTArray<nsString>& aParticipants,
-                                         const uint64_t aTimestamp,
+                                         uint64_t aTimestamp,
                                          const nsString& aLastMessageSubject,
                                          const nsString& aBody,
-                                         const uint64_t aUnreadCount,
+                                         uint64_t aUnreadCount,
                                          MessageType aLastMessageType)
   : mData(aId, aParticipants, aTimestamp, aLastMessageSubject, aBody,
           aUnreadCount, aLastMessageType)
 {
   MOZ_ASSERT(aParticipants.Length());
 }
 
 MobileMessageThread::MobileMessageThread(const ThreadData& aData)
--- a/dom/mobilemessage/src/MobileMessageThread.h
+++ b/dom/mobilemessage/src/MobileMessageThread.h
@@ -18,32 +18,32 @@ class MobileMessageThread MOZ_FINAL : pu
 {
 private:
   typedef mobilemessage::ThreadData ThreadData;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZMOBILEMESSAGETHREAD
 
-  MobileMessageThread(const uint64_t aId,
+  MobileMessageThread(uint64_t aId,
                       const nsTArray<nsString>& aParticipants,
-                      const uint64_t aTimestamp,
+                      uint64_t aTimestamp,
                       const nsString& aLastMessageSubject,
                       const nsString& aBody,
-                      const uint64_t aUnreadCount,
+                      uint64_t aUnreadCount,
                       mobilemessage::MessageType aLastMessageType);
 
   MobileMessageThread(const ThreadData& aData);
 
-  static nsresult Create(const uint64_t aId,
+  static nsresult Create(uint64_t aId,
                          const JS::Value& aParticipants,
-                         const JS::Value& aTimestamp,
+                         uint64_t aTimestamp,
                          const nsAString& aLastMessageSubject,
                          const nsAString& aBody,
-                         const uint64_t aUnreadCount,
+                         uint64_t aUnreadCount,
                          const nsAString& aLastMessageType,
                          JSContext* aCx,
                          nsIDOMMozMobileMessageThread** aThread);
 
   const ThreadData& GetData() const { return mData; }
 
 private:
   // Don't try to use the default constructor.
--- a/dom/mobilemessage/src/SmsMessage.cpp
+++ b/dom/mobilemessage/src/SmsMessage.cpp
@@ -3,17 +3,16 @@
  * 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 "SmsMessage.h"
 #include "nsIDOMClassInfo.h"
 #include "jsapi.h" // For OBJECT_TO_JSVAL and JS_NewDateObjectMsec
 #include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch
 #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
-#include "MessageUtils.h"
 
 using namespace mozilla::dom::mobilemessage;
 
 DOMCI_DATA(MozSmsMessage, mozilla::dom::SmsMessage)
 
 namespace mozilla {
 namespace dom {
 
@@ -55,20 +54,20 @@ SmsMessage::Create(int32_t aId,
                    uint64_t aThreadId,
                    const nsAString& aIccId,
                    const nsAString& aDelivery,
                    const nsAString& aDeliveryStatus,
                    const nsAString& aSender,
                    const nsAString& aReceiver,
                    const nsAString& aBody,
                    const nsAString& aMessageClass,
-                   const JS::Value& aTimestamp,
-                   const JS::Value& aSentTimestamp,
-                   const JS::Value& aDeliveryTimestamp,
-                   const bool aRead,
+                   uint64_t aTimestamp,
+                   uint64_t aSentTimestamp,
+                   uint64_t aDeliveryTimestamp,
+                   bool aRead,
                    JSContext* aCx,
                    nsIDOMMozSmsMessage** aMessage)
 {
   *aMessage = nullptr;
 
   // SmsMessageData exposes these as references, so we can simply assign
   // to them.
   SmsMessageData data;
@@ -114,26 +113,23 @@ SmsMessage::Create(int32_t aId,
     data.messageClass() = eMessageClass_Class2;
   } else if (aMessageClass.Equals(MESSAGE_CLASS_CLASS_3)) {
     data.messageClass() = eMessageClass_Class3;
   } else {
     return NS_ERROR_INVALID_ARG;
   }
 
   // Set |timestamp|.
-  nsresult rv = convertTimeToInt(aCx, aTimestamp, data.timestamp());
-  NS_ENSURE_SUCCESS(rv, rv);
+  data.timestamp() = aTimestamp;
 
   // Set |sentTimestamp|.
-  rv = convertTimeToInt(aCx, aSentTimestamp, data.sentTimestamp());
-  NS_ENSURE_SUCCESS(rv, rv);
+  data.sentTimestamp() = aSentTimestamp;
 
   // Set |deliveryTimestamp|.
-  rv = convertTimeToInt(aCx, aDeliveryTimestamp, data.deliveryTimestamp());
-  NS_ENSURE_SUCCESS(rv, rv);
+  data.deliveryTimestamp() = aDeliveryTimestamp;
 
   nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(data);
   message.swap(*aMessage);
   return NS_OK;
 }
 
 const SmsMessageData&
 SmsMessage::GetData() const
--- a/dom/mobilemessage/src/SmsMessage.h
+++ b/dom/mobilemessage/src/SmsMessage.h
@@ -29,31 +29,32 @@ public:
              const nsString& aSender,
              const nsString& aReceiver,
              const nsString& aBody,
              mobilemessage::MessageClass aMessageClass,
              uint64_t aTimestamp,
              uint64_t aSentTimestamp,
              uint64_t aDeliveryTimestamp,
              bool aRead);
+
   SmsMessage(const mobilemessage::SmsMessageData& aData);
 
   static nsresult Create(int32_t aId,
                          uint64_t aThreadId,
                          const nsAString& aIccId,
                          const nsAString& aDelivery,
                          const nsAString& aDeliveryStatus,
                          const nsAString& aSender,
                          const nsAString& aReceiver,
                          const nsAString& aBody,
                          const nsAString& aMessageClass,
-                         const JS::Value& aTimestamp,
-                         const JS::Value& aSentTimestamp,
-                         const JS::Value& aDeliveryTimestamp,
-                         const bool aRead,
+                         uint64_t aTimestamp,
+                         uint64_t aSentTimestamp,
+                         uint64_t aDeliveryTimestamp,
+                         bool aRead,
                          JSContext* aCx,
                          nsIDOMMozSmsMessage** aMessage);
   const mobilemessage::SmsMessageData& GetData() const;
 
 private:
   // Don't try to use the default constructor.
   SmsMessage();
 
--- a/dom/mobilemessage/src/android/SmsService.cpp
+++ b/dom/mobilemessage/src/android/SmsService.cpp
@@ -32,20 +32,20 @@ SmsService::GetSegmentInfoForText(const 
 
   nsresult rv = AndroidBridge::Bridge()->GetSegmentInfoForText(aText, aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsService::Send(uint32_t         aServiceId,
+SmsService::Send(uint32_t aServiceId,
                  const nsAString& aNumber,
                  const nsAString& aMessage,
-                 const bool       aSilent,
+                 bool aSilent,
                  nsIMobileMessageCallback* aRequest)
 {
   if (!AndroidBridge::Bridge()) {
     return NS_OK;
   }
 
   AndroidBridge::Bridge()->SendMessage(aNumber, aMessage, aRequest);
   return NS_OK;
--- a/dom/mobilemessage/src/gonk/SmsService.cpp
+++ b/dom/mobilemessage/src/gonk/SmsService.cpp
@@ -92,20 +92,20 @@ SmsService::GetSegmentInfoForText(const 
     mRil->GetRadioInterface(0, getter_AddRefs(radioInterface));
   }
   NS_ENSURE_TRUE(radioInterface, NS_ERROR_FAILURE);
 
   return radioInterface->GetSegmentInfoForText(aText, aRequest);
 }
 
 NS_IMETHODIMP
-SmsService::Send(uint32_t         aServiceId,
+SmsService::Send(uint32_t aServiceId,
                  const nsAString& aNumber,
                  const nsAString& aMessage,
-                 const bool       aSilent,
+                 bool aSilent,
                  nsIMobileMessageCallback* aRequest)
 {
   nsCOMPtr<nsIRadioInterface> radioInterface;
   if (mRil) {
     mRil->GetRadioInterface(aServiceId, getter_AddRefs(radioInterface));
   }
   NS_ENSURE_TRUE(radioInterface, NS_ERROR_FAILURE);
 
--- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp
@@ -160,17 +160,17 @@ SmsIPCService::GetSmscAddress(uint32_t a
 {
   return SendRequest(GetSmscAddressRequest(aServiceId), aRequest);
 }
 
 NS_IMETHODIMP
 SmsIPCService::Send(uint32_t aServiceId,
                     const nsAString& aNumber,
                     const nsAString& aMessage,
-                    const bool aSilent,
+                    bool aSilent,
                     nsIMobileMessageCallback* aRequest)
 {
   return SendRequest(SendMessageRequest(SendSmsMessageRequest(aServiceId,
                                                               nsString(aNumber),
                                                               nsString(aMessage),
                                                               aSilent)),
                      aRequest);
 }
--- a/dom/mobilemessage/src/ipc/SmsTypes.ipdlh
+++ b/dom/mobilemessage/src/ipc/SmsTypes.ipdlh
@@ -89,22 +89,22 @@ struct SmsFilterData
   nsString[]    numbers;
   DeliveryState delivery;
   ReadState     read;
   uint64_t      threadId;
 };
 
 struct ThreadData
 {
-  uint64_t id;
-  nsString[] participants;
-  uint64_t timestamp;
-  nsString lastMessageSubject;
-  nsString body;
-  uint64_t unreadCount;
+  uint64_t    id;
+  nsString[]  participants;
+  uint64_t    timestamp;
+  nsString    lastMessageSubject;
+  nsString    body;
+  uint64_t    unreadCount;
   MessageType lastMessageType;
 };
 
 union MobileMessageCursorData
 {
   MmsMessageData;
   SmsMessageData;
   ThreadData;
--- a/dom/mobilemessage/tests/test_smsservice_createsmsmessage.js
+++ b/dom/mobilemessage/tests/test_smsservice_createsmsmessage.js
@@ -28,17 +28,17 @@ function run_test() {
   run_next_test();
 }
 
 /**
  * Ensure an SmsMessage object created has sensible initial values.
  */
 add_test(function test_interface() {
   let sms = newMessage(null, null, ICC_ID, "sent", "success", null, null, null,
-                       "normal", new Date(), new Date(), new Date(), true);
+                       "normal", Date.now(), Date.now(), Date.now(), true);
   do_check_true(sms instanceof Ci.nsIDOMMozSmsMessage);
   do_check_eq(sms.id, 0);
   do_check_eq(sms.threadId, 0);
   do_check_eq(sms.iccId, ICC_ID);
   do_check_eq(sms.delivery, "sent");
   do_check_eq(sms.deliveryStatus, "success");
   do_check_eq(sms.receiver, null);
   do_check_eq(sms.sender, null);
@@ -48,17 +48,17 @@ add_test(function test_interface() {
   run_next_test();
 });
 
 /**
  * Test if ICC ID is null when it's not available.
  */
 add_test(function test_icc_id_not_available() {
   let sms = newMessage(null, null, null, "sent", "success", null, null, null,
-                       "normal", new Date(), new Date(), new Date(), true);
+                       "normal", Date.now(), Date.now(), Date.now(), true);
   do_check_true(sms instanceof Ci.nsIDOMMozSmsMessage);
   do_check_eq(sms.id, 0);
   do_check_eq(sms.threadId, 0);
   do_check_eq(sms.iccId, null);
   do_check_eq(sms.delivery, "sent");
   do_check_eq(sms.deliveryStatus, "success");
   do_check_eq(sms.receiver, null);
   do_check_eq(sms.sender, null);
@@ -68,17 +68,17 @@ add_test(function test_icc_id_not_availa
   run_next_test();
 });
 
 /**
  * Verify that attributes are read-only.
  */
 add_test(function test_readonly_attributes() {
   let sms = newMessage(null, null, ICC_ID, "sent", "success", null, null, null,
-                       "normal", new Date(), new Date(), new Date(), true);
+                       "normal", Date.now(), Date.now(), Date.now(), true);
 
   sms.id = 1;
   do_check_eq(sms.id, 0);
 
   sms.threadId = 1;
   do_check_eq(sms.threadId, 0);
 
   sms.iccId = "987654321";
@@ -139,17 +139,18 @@ add_test(function test_timestamp_number(
   do_check_eq(sms.timestamp, ts);
   do_check_eq(sms.sentTimestamp, ts);
   do_check_eq(sms.deliveryTimestamp, ts);
   do_check_true(sms.read);
   run_next_test();
 });
 
 /**
- * Test supplying the timestamp as a Date object.
+ * Test supplying the timestamp as a Date object, which will be automatically
+ * casted to unsigned long long.
  */
 add_test(function test_timestamp_date() {
   let date = new Date();
   let sms = newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
                        "the body", "normal", date, date, date, true);
   do_check_eq(sms.id, 42);
   do_check_eq(sms.threadId, 1);
   do_check_eq(sms.iccId, ICC_ID);
@@ -162,172 +163,72 @@ add_test(function test_timestamp_date() 
   do_check_eq(sms.timestamp, date.getTime());
   do_check_eq(sms.sentTimestamp, date.getTime());
   do_check_eq(sms.deliveryTimestamp, date.getTime());
   do_check_true(sms.read);
   run_next_test();
 });
 
 /**
- * Test that a floating point number for the timestamp is not allowed.
- */
-add_test(function test_invalid_timestamp_float() {
-  // Test timestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", 3.1415, new Date(), new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test sentTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), 3.1415, new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test deliveryTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), new Date(), 3.1415, true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  run_next_test();
-});
-
-/**
- * Test that a null value for the timestamp is not allowed.
- */
-add_test(function test_invalid_timestamp_null() {
-  // Test timestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", null, new Date(), new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test sentTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), null, new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test deliveryTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), new Date(), null, true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  run_next_test();
-});
-
-/**
- * Test that undefined for the timestamp is not allowed.
- */
-add_test(function test_invalid_timestamp_undefined() {
-  // Test timestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", undefined, new Date(), new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test sentTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), undefined, new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test deliveryTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), new Date(), undefined, true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  run_next_test();
-});
-
-/**
- * Test that a random object for the timestamp is not allowed.
- */
-add_test(function test_invalid_timestamp_object() {
-  // Test timestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", {}, new Date(), new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test sentTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), {}, new Date(), true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  // Test deliveryTimestamp.
-  do_check_throws(function() {
-    newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "normal", new Date(), new Date(), {}, true);
-  }, Cr.NS_ERROR_INVALID_ARG);
-
-  run_next_test();
-});
-
-/**
  * Test that an invalid delivery string is not accepted.
  */
 add_test(function test_invalid_delivery_string() {
   do_check_throws(function() {
     newMessage(42, 1, ICC_ID, "this is invalid", "pending", "the sender",
-               "the receiver", "the body", "normal", new Date(), 0, 0, true);
+               "the receiver", "the body", "normal", Date.now(), 0, 0, true);
   }, Cr.NS_ERROR_INVALID_ARG);
   run_next_test();
 });
 
 /**
  * Test that a number is not accepted for the 'delivery' argument.
  */
 add_test(function test_invalid_delivery_string() {
   do_check_throws(function() {
     newMessage(42, 1, ICC_ID, 1, "pending", "the sender", "the receiver", "the body",
-               "normal", new Date(), 0, 0, true);
+               "normal", Date.now(), 0, 0, true);
   }, Cr.NS_ERROR_INVALID_ARG);
   run_next_test();
 });
 
 /**
  * Test that an invalid delivery status string is not accepted.
  */
 add_test(function test_invalid_delivery_status_string() {
   do_check_throws(function() {
     newMessage(42, 1, ICC_ID, "sent", "this is invalid", "the sender", "the receiver",
-               "the body", "normal", new Date(), new Date(), 0, true);
+               "the body", "normal", Date.now(), Date.now(), 0, true);
   }, Cr.NS_ERROR_INVALID_ARG);
   run_next_test();
 });
 
 /**
  * Test that a number is not accepted for the 'deliveryStatus' argument.
  */
 add_test(function test_invalid_delivery_status_string() {
   do_check_throws(function() {
     newMessage(42, 1, ICC_ID, "sent", 1, "the sender", "the receiver", "the body",
-               "normal", new Date(), new Date(), 0, true);
+               "normal", Date.now(), Date.now(), 0, true);
   }, Cr.NS_ERROR_INVALID_ARG);
   run_next_test();
 });
 
 /**
  * Test that an invalid message class string is not accepted.
  */
 add_test(function test_invalid_message_class_string() {
   do_check_throws(function() {
     newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", "this is invalid", new Date(), new Date(), new Date(), true);
+               "the body", "this is invalid", Date.now(), Date.now(), Date.now(), true);
   }, Cr.NS_ERROR_INVALID_ARG);
   run_next_test();
 });
 
 /**
  * Test that a number is not accepted for the 'messageClass' argument.
  */
 add_test(function test_invalid_message_class_string() {
   do_check_throws(function() {
     newMessage(42, 1, ICC_ID, "sent", "success", "the sender", "the receiver",
-               "the body", 1, new Date(), new Date(), new Date(), true);
+               "the body", 1, Date.now(), Date.now(), Date.now(), true);
   }, Cr.NS_ERROR_INVALID_ARG);
   run_next_test();
 });
--- a/dom/permission/tests/test_wifi-manage.html
+++ b/dom/permission/tests/test_wifi-manage.html
@@ -25,17 +25,17 @@ function verifier(success, failure) {
   }
 }
 
 var gData = [
   {
     perm: ["wifi-manage"],
     needParentPerm: true,
     obj: "mozWifiManager",
-    idl: "nsIDOMWifiManager",
+    webidl: "MozWifiManager",
     verifier: verifier.toSource(),
   },
 ]
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/system/gonk/NetworkInterfaceListService.js
+++ b/dom/system/gonk/NetworkInterfaceListService.js
@@ -33,17 +33,20 @@ NetworkInterfaceListService.prototype = 
           excludeSupl: (aConditions &
                         Ci.nsINetworkInterfaceListService.
                         LIST_NOT_INCLUDE_SUPL_INTERFACES) != 0,
           excludeMms: (aConditions &
                        Ci.nsINetworkInterfaceListService.
                        LIST_NOT_INCLUDE_MMS_INTERFACES) != 0,
           excludeIms: (aConditions &
                        Ci.nsINetworkInterfaceListService.
-                       LIST_NOT_INCLUDE_IMS_INTERFACES) != 0
+                       LIST_NOT_INCLUDE_IMS_INTERFACES) != 0,
+          excludeDun: (aConditions &
+                       Ci.nsINetworkInterfaceListService.
+                       LIST_NOT_INCLUDE_DUN_INTERFACES) != 0
         }
       )[0]);
   }
 };
 
 function NetworkInterfaceList (aInterfaces) {
   this._interfaces = aInterfaces;
 }
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -447,17 +447,18 @@ NetworkManager.prototype = {
     this._overriddenActive = network;
     this.setAndConfigureActive();
   },
 
 #ifdef MOZ_B2G_RIL
   isNetworkTypeSecondaryMobile: function(type) {
     return (type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS ||
             type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL ||
-            type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS);
+            type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS ||
+            type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN);
   },
 
   isNetworkTypeMobile: function(type) {
     return (type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE ||
             this.isNetworkTypeSecondaryMobile(type));
   },
 
   setExtraHostRoute: function(network) {
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -59,21 +59,21 @@ SOURCES += [
 
 if CONFIG['ENABLE_TESTS']:
     XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini']
 
 EXTRA_COMPONENTS += [
     'NetworkInterfaceListService.js',
     'NetworkInterfaceListService.manifest',
     'NetworkManager.manifest',
+    'NetworkService.js',
     'NetworkService.manifest',
 ]
 EXTRA_PP_COMPONENTS += [
     'NetworkManager.js',
-    'NetworkService.js',
 ]
 EXTRA_JS_MODULES += [
     'systemlibs.js',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIRadioInterfaceLayer.idl',
--- a/dom/system/gonk/tests/marionette/test_data_connection.js
+++ b/dom/system/gonk/tests/marionette/test_data_connection.js
@@ -54,17 +54,17 @@ function getSetting(key) {
   return deferred.promise;
 }
 
 function setEmulatorAPN() {
   let apn = [
     [{"carrier":"T-Mobile US",
       "apn":"epc.tmobile.com",
       "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc",
-      "types":["default","supl","mms","ims"]}]
+      "types":["default","supl","mms","ims","dun"]}]
   ];
 
   return setSetting(APN_KEY, apn);
 }
 
 function waitNetworkConnected(networkType) {
   log("wait network " + networkType + " connected");
 
@@ -150,17 +150,18 @@ function testNonDefaultDataConnection() 
   log("= testNonDefaultDataConnection =");
 
   function doTestNonDefaultDataConnection(type) {
     log("doTestNonDefaultDataConnection: " + type);
 
     let typeMapping = {
       "mms": Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS,
       "supl": Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL,
-      "ims": Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS
+      "ims": Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS,
+      "dun": Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN
     };
     let networkType = typeMapping[type];
 
     return Promise.resolve()
       .then(() => radioInterface.setupDataCallByType(type))
       .then(() => waitNetworkConnected(networkType))
       .then(() => radioInterface.deactivateDataCallByType(type))
       .then(() => waitNetworkDisconnected(networkType));
@@ -171,16 +172,17 @@ function testNonDefaultDataConnection() 
     .then(() => getSetting(APN_KEY))
     .then(value => {
       currentApn = value;
     })
     .then(setEmulatorAPN)
     .then(() => doTestNonDefaultDataConnection("mms"))
     .then(() => doTestNonDefaultDataConnection("supl"))
     .then(() => doTestNonDefaultDataConnection("ims"))
+    .then(() => doTestNonDefaultDataConnection("dun"))
     // Restore APN settings
     .then(() => setSetting(APN_KEY, currentApn))
     .then(null, () => {
       ok(false, "promise rejected during test");
     })
     .then(runNextTest);
 }
 
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -673,18 +673,26 @@ var interfaceNamesInGlobalScope =
     {name: "MozTimeManager", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozVoicemail", b2g: true, pref: "dom.voicemail.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozVoicemailEvent", b2g: true, pref: "dom.voicemail.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWakeLock", b2g: true, pref: "dom.wakelock.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MozWifiConnection", b2g: true, permission: "wifi-manage"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MozWifiConnectionInfo", b2g: true, permission: "wifi-manage"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiConnectionInfoEvent", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MozWifiManager", b2g: true, permission: "wifi-manage"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MozWifiNetwork", b2g: true, permission: "wifi-manage"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiStatusChangeEvent", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pGroupOwner", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pManager", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pStatusChangeEvent", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/MediaRecorder.webidl
+++ b/dom/webidl/MediaRecorder.webidl
@@ -7,17 +7,17 @@
  * https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 enum RecordingState { "inactive", "recording", "paused" };
 
-[Constructor(MediaStream stream)]
+[Constructor(MediaStream stream, optional MediaRecorderOptions options)]
 interface MediaRecorder : EventTarget {
 
   readonly attribute MediaStream stream;
 
   readonly attribute RecordingState state;
 
   readonly attribute DOMString mimeType;
 
@@ -40,8 +40,11 @@ interface MediaRecorder : EventTarget {
 
   [Throws]
   void resume();
 
   [Throws]
   void requestData();
 };
 
+dictionary MediaRecorderOptions {
+  DOMString mimeType = ""; // Default encoding mimeType.
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozWifiManager.webidl
@@ -0,0 +1,237 @@
+/* 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/. */
+
+enum WifiWPSMethod {
+  "pbc",
+  "pin",
+  "cancel"
+};
+
+enum ConnectionStatus {
+  "connecting",
+  "associated",
+  "connected",
+  "disconnected"
+};
+
+dictionary WifiWPSInfo {
+  WifiWPSMethod method;
+  DOMString? pin;
+  DOMString? bssid;
+};
+
+dictionary NetworkProperties {
+  DOMString ssid;
+  sequence<DOMString>? security;
+  sequence<DOMString>? capabilities;
+  boolean known;
+  boolean connected;
+  boolean hidden;
+};
+
+[Constructor(optional NetworkProperties properties),
+ JSImplementation="@mozilla.org/mozwifinetwork;1"]
+interface MozWifiNetwork {
+  readonly attribute DOMString ssid;
+  readonly attribute any security;
+  readonly attribute any capabilities;
+  readonly attribute boolean known;
+  readonly attribute boolean connected;
+  readonly attribute boolean hidden;
+
+           attribute DOMString? bssid;
+           attribute DOMString? signalStrength;
+           attribute long? relSignalStrength;
+           attribute DOMString? psk;
+           attribute DOMString? keyManagement;
+           attribute DOMString? identity;
+           attribute DOMString? password;
+           attribute DOMString? phase1;
+           attribute DOMString? phase2;
+           attribute DOMString? eap;
+           attribute DOMString? pin;
+};
+
+[JSImplementation="@mozilla.org/mozwificonnection;1"]
+interface MozWifiConnection {
+  readonly attribute ConnectionStatus status;
+  readonly attribute MozWifiNetwork? network;
+};
+
+[JSImplementation="@mozilla.org/mozwificonnectioninfo;1"]
+interface MozWifiConnectionInfo {
+  readonly attribute short signalStrength;
+  readonly attribute short relSignalStrength;
+  readonly attribute long linkSpeed;
+  readonly attribute DOMString? ipAddress;
+};
+
+dictionary IPConfiguration {
+  boolean enabled;
+  DOMString ipaddr;
+  DOMString proxy;
+  short maskLength;
+  DOMString gateway;
+  DOMString dns1;
+  DOMString dns2;
+};
+
+[JSImplementation="@mozilla.org/wifimanager;1",
+ NavigatorProperty="mozWifiManager",
+ Func="Navigator::HasWifiManagerSupport"]
+interface MozWifiManager : EventTarget {
+  /**
+   * Returns the list of currently available networks.
+   * onsuccess: We have obtained the current list of networks. request.value
+   *            is an object whose property names are SSIDs and values are
+   *            network objects.
+   * onerror: We were unable to obtain a list of property names.
+   */
+  DOMRequest getNetworks();
+
+  /**
+   * Returns the list of networks known to the system that will be
+   * automatically connected to if they're in range.
+   * onsuccess: request.value is an object whose property names are
+   *            SSIDs and values are network objects.
+   * onerror: We were unable to obtain a list of known networks.
+   */
+  DOMRequest getKnownNetworks();
+
+  /**
+   * Takes one of the networks returned from getNetworks and tries to
+   * connect to it.
+   * @param network A network object with information about the network,
+   *                such as the SSID, key management desired, etc.
+   * onsuccess: We have started attempting to associate with the network.
+   *            request.value is true.
+   * onerror: We were unable to select the network. This most likely means a
+   *          configuration error.
+   */
+  DOMRequest associate(MozWifiNetwork network);
+
+  /**
+   * Given a network, removes it from the list of networks that we'll
+   * automatically connect to. In order to re-connect to the network, it is
+   * necessary to call associate on it.
+   * @param network A network object with the SSID of the network to remove.
+   * onsuccess: We have removed this network. If we were previously
+   *            connected to it, we have started reconnecting to the next
+   *            network in the list.
+   * onerror: We were unable to remove the network.
+   */
+  DOMRequest forget(MozWifiNetwork network);
+
+  /**
+   * Wi-Fi Protected Setup functionality.
+   * @param detail WPS detail which has 'method' and 'pin' field.
+   *               The possible method field values are:
+   *                 - pbc: The Push Button Configuration.
+   *                 - pin: The PIN configuration.
+   *                 - cancel: Request to cancel WPS in progress.
+   *               If method field is 'pin', 'pin' field can exist and has
+   *               a PIN number.
+   *               If method field is 'pin', 'bssid' field can exist and has
+   *               a opposite BSSID.
+   * onsuccess: We have successfully started/canceled wps.
+   * onerror: We have failed to start/cancel wps.
+   */
+  DOMRequest wps(optional WifiWPSInfo detail);
+
+  /**
+   * Turn on/off wifi power saving mode.
+   * @param enabled true or false.
+   * onsuccess: We have successfully turn on/off wifi power saving mode.
+   * onerror: We have failed to turn on/off wifi power saving mode.
+   */
+  DOMRequest setPowerSavingMode(boolean enabled);
+
+  /**
+   * Given a network, configure using static IP instead of running DHCP
+   * @param network A network object with the SSID of the network to set static ip.
+   * @param info info should have following field:
+   *        - enabled True to enable static IP, false to use DHCP
+   *        - ipaddr configured static IP address
+   *        - proxy configured proxy server address
+   *        - maskLength configured mask length
+   *        - gateway configured gateway address
+   *        - dns1 configured first DNS server address
+   *        - dns2 configured seconf DNS server address
+   * onsuccess: We have successfully configure the static ip mode.
+   * onerror: We have failed to configure the static ip mode.
+   */
+  DOMRequest setStaticIpMode(MozWifiNetwork network, optional IPConfiguration info);
+
+  /**
+   * Given a network, configure http proxy when using wifi.
+   * @param network A network object with the SSID of the network to set http proxy.
+   * @param info info should have following field:
+   *        - httpProxyHost ip address of http proxy.
+   *        - httpProxyPort port of http proxy, set 0 to use default port 8080.
+   *        set info to null to clear http proxy.
+   * onsuccess: We have successfully configure http proxy.
+   * onerror: We have failed to configure http proxy.
+   */
+  DOMRequest setHttpProxy(MozWifiNetwork network, any info);
+
+  /**
+   * Returns whether or not wifi is currently enabled.
+   */
+  readonly attribute boolean enabled;
+
+  /**
+   * Returns the MAC address of the wifi adapter.
+   */
+  readonly attribute DOMString macAddress;
+
+  /**
+   * An non-null object containing the following information:
+   *  - status ("disconnected", "connecting", "associated", "connected")
+   *  - network
+   *
+   *  Note that the object returned is read only. Any changes required must
+   *  be done by calling other APIs.
+   */
+  readonly attribute MozWifiConnection? connection;
+
+  /**
+   * A connectionInformation object with the same information found in an
+   * nsIDOMMozWifiConnectionInfoEvent (but without the network).
+   * If we are not currently connected to a network, this will be null.
+   */
+  readonly attribute MozWifiConnectionInfo? connectionInformation;
+
+  /**
+   * State notification listeners. These all take an
+   * nsIDOMMozWifiStatusChangeEvent with the new status and a network (which
+   * may be null).
+   *
+   * The possible statuses are:
+   *   - connecting: Fires when we start the process of connecting to a
+   *                 network.
+   *   - associated: Fires when we have connected to an access point but do
+   *                 not yet have an IP address.
+   *   - connected: Fires once we are fully connected to an access point and
+   *                can access the internet.
+   *   - disconnected: Fires when we either fail to connect to an access
+   *                   point (transition: associated -> disconnected) or
+   *                   when we were connected to a network but have
+   *                   disconnected for any reason (transition: connected ->
+   *                   disconnected).
+   */
+  attribute EventHandler onstatuschange;
+
+  /**
+   * An event listener that is called with information about the signal
+   * strength and link speed every 5 seconds.
+   */
+  attribute EventHandler onconnectionInfoUpdate;
+
+  /**
+   * These two events fire when the wifi system is brought online or taken
+   * offline.
+   */
+  attribute EventHandler onenabled;
+  attribute EventHandler ondisabled;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -548,16 +548,17 @@ if CONFIG['MOZ_NFC']:
          'MozNFCPeer.webidl',
          'MozNFCTag.webidl',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     WEBIDL_FILES += [
         'MozSpeakerManager.webidl',
         'MozWifiConnectionInfoEvent.webidl',
+        'MozWifiManager.webidl',
         'MozWifiP2pManager.webidl',
         'MozWifiP2pStatusChangeEvent.webidl',
         'MozWifiStatusChangeEvent.webidl',
     ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     WEBIDL_FILES += [
         'SpeechRecognitionError.webidl',
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -10,77 +10,84 @@ const {classes: Cc, interfaces: Ci, util
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
 const DEBUG = false; // set to false to suppress debug messages
 
 const DOMWIFIMANAGER_CONTRACTID = "@mozilla.org/wifimanager;1";
-const DOMWIFIMANAGER_CID        = Components.ID("{2cf775a7-1837-410c-9e26-323c42e076da}");
+const DOMWIFIMANAGER_CID        = Components.ID("{c9b5f09e-25d2-40ca-aef4-c4d13d93c706}");
 
-function DOMWifiManager() {
-}
-
-function exposeCurrentNetwork(currentNetwork) {
-  currentNetwork.__exposedProps__ = exposeCurrentNetwork.currentNetworkApi;
+function MozWifiNetwork() {
 }
 
-exposeCurrentNetwork.currentNetworkApi = {
-  ssid: "r",
-  security: "r",
-  capabilities: "r",
-  known: "r"
+MozWifiNetwork.prototype = {
+
+  init: function(aWindow) {
+    this._window = aWindow;
+  },
+
+  __init: function(obj) {
+    this.ssid = obj.ssid;
+    this.security = obj.security;
+    this.capabilities = obj.capabilities;
+    this.known = obj.known;
+    this.connected = obj.connected;
+    this.hidden = obj.hidden;
+  },
+
+  classID: Components.ID("{c01fd751-43c0-460a-8b64-abf652ec7220}"),
+  contractID: "@mozilla.org/mozwifinetwork;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
+                                         Ci.nsIDOMGlobalPropertyInitializer])
 };
 
-// For smaller, read-only APIs, we expose any property that doesn't begin with
-// an underscore.
-function exposeReadOnly(obj) {
-  var exposedProps = {};
-  for (let i in obj) {
-    if (i[0] === "_")
-      continue;
-    exposedProps[i] = "r";
-  }
+function MozWifiConnection(obj) {
+  this.status = obj.status;
+  this.network = obj.network;
+}
+
+MozWifiConnection.prototype = {
+  classID: Components.ID("{23579da4-201b-4319-bd42-9b7f337343ac}"),
+  contractID: "@mozilla.org/mozwificonnection;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+};
 
-  obj.__exposedProps__ = exposedProps;
-  return obj;
+function MozWifiConnectionInfo(obj) {
+  this.signalStrength = obj.signalStrength;
+  this.relSignalStrength = obj.relSignalStrength;
+  this.linkSpeed = obj.linkSpeed;
+  this.ipAddress = obj.ipAddress;
+}
+
+MozWifiConnectionInfo.prototype = {
+  classID: Components.ID("{83670352-6ed4-4c35-8de9-402296a1959c}"),
+  contractID: "@mozilla.org/mozwificonnectioninfo;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+}
+
+function DOMWifiManager() {
+  this.defineEventHandlerGetterSetter("onstatuschange");
+  this.defineEventHandlerGetterSetter("onconnectionInfoUpdate");
+  this.defineEventHandlerGetterSetter("onenabled");
+  this.defineEventHandlerGetterSetter("ondisabled");
 }
 
 DOMWifiManager.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
-
-  classID:   DOMWIFIMANAGER_CID,
-  classInfo: XPCOMUtils.generateCI({classID: DOMWIFIMANAGER_CID,
-                                    contractID: DOMWIFIMANAGER_CONTRACTID,
-                                    classDescription: "DOMWifiManager",
-                                    interfaces: [Ci.nsIDOMWifiManager],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT}),
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMWifiManager,
-                                         Ci.nsIDOMGlobalPropertyInitializer,
+  classDescription: "DOMWifiManager",
+  classID: DOMWIFIMANAGER_CID,
+  contractID: DOMWIFIMANAGER_CONTRACTID,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsIObserver]),
 
   // nsIDOMGlobalPropertyInitializer implementation
   init: function(aWindow) {
-    let principal = aWindow.document.nodePrincipal;
-    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
-
-    let perm = principal == secMan.getSystemPrincipal()
-                 ? Ci.nsIPermissionManager.ALLOW_ACTION
-                 : Services.perms.testExactPermissionFromPrincipal(principal, "wifi-manage");
-
-    // Only pages with perm set can use the wifi manager.
-    this._hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
-
-    if (!this._hasPrivileges) {
-      return null;
-    }
-
     // Maintain this state for synchronous APIs.
     this._currentNetwork = null;
     this._connectionStatus = "disconnected";
     this._enabled = false;
     this._lastConnectionInfo = null;
 
     const messages = ["WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO",
                       "WifiManager:getKnownNetworks:Return:OK", "WifiManager:getKnownNetworks:Return:NO",
@@ -96,37 +103,64 @@ DOMWifiManager.prototype = {
                       "WifiManager:onwpstimeout", "WifiManager:onwpsfail",
                       "WifiManager:onwpsoverlap", "WifiManager:connectionInfoUpdate",
                       "WifiManager:onconnectingfailed"];
     this.initDOMRequestHelper(aWindow, messages);
     this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
 
     var state = this._mm.sendSyncMessage("WifiManager:getState")[0];
     if (state) {
-      this._currentNetwork = state.network;
-      if (this._currentNetwork)
-        exposeCurrentNetwork(this._currentNetwork);
-      this._lastConnectionInfo = state.connectionInfo;
+      this._currentNetwork = this._convertWifiNetwork(state.network);
+      this._lastConnectionInfo = this._convertConnectionInfo(state.connectionInfo);
       this._enabled = state.enabled;
       this._connectionStatus = state.status;
       this._macAddress = state.macAddress;
     } else {
       this._currentNetwork = null;
       this._lastConnectionInfo = null;
       this._enabled = false;
       this._connectionStatus = "disconnected";
       this._macAddress = "";
     }
   },
 
-  uninit: function() {
-    this._onStatusChange = null;
-    this._onConnectionInfoUpdate = null;
-    this._onEnabled = null;
-    this._onDisabled = null;
+  _convertWifiNetworkToJSON: function(aNetwork) {
+    let json = {};
+
+    for (let key in aNetwork) {
+      // In WifiWorker.js there are lots of check using "key in network".
+      // So if the value of any property of WifiNetwork is undefined, do not clone it.
+      if (aNetwork[key] != undefined) {
+        json[key] = aNetwork[key];
+      }
+    }
+    return json;
+  },
+
+  _convertWifiNetwork: function(aNetwork) {
+    let network = aNetwork ? new this._window.MozWifiNetwork(aNetwork) : null;
+    return network;
+  },
+
+  _convertWifiNetworks: function(aNetworks) {
+    let networks = [];
+    for (let i in aNetworks) {
+      networks.push(this._convertWifiNetwork(aNetworks[i]));
+    }
+    return networks;
+  },
+
+  _convertConnection: function(aConn) {
+    let conn = aConn ? new MozWifiConnection(aConn) : null;
+    return conn;
+  },
+
+  _convertConnectionInfo: function(aInfo) {
+    let info = aInfo ? new MozWifiConnectionInfo(aInfo) : null;
+    return info;
   },
 
   _sendMessageForRequest: function(name, data, request) {
     let id = this.getRequestId(request);
     this._mm.sendAsyncMessage(name, { data: data, rid: id, mid: this._id });
   },
 
   receiveMessage: function(aMessage) {
@@ -139,25 +173,25 @@ DOMWifiManager.prototype = {
       request = this.takeRequest(msg.rid);
       if (!request) {
         return;
       }
     }
 
     switch (aMessage.name) {
       case "WifiManager:getNetworks:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, this._convertWifiNetworks(msg.data));
         break;
 
       case "WifiManager:getNetworks:Return:NO":
         Services.DOMRequest.fireError(request, "Unable to scan for networks");
         break;
 
       case "WifiManager:getKnownNetworks:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, this._convertWifiNetworks(msg.data));
         break;
 
       case "WifiManager:getKnownNetworks:Return:NO":
         Services.DOMRequest.fireError(request, "Unable to get known networks");
         break;
 
       case "WifiManager:associate:Return:OK":
         Services.DOMRequest.fireSuccess(request, true);
@@ -171,41 +205,41 @@ DOMWifiManager.prototype = {
         Services.DOMRequest.fireSuccess(request, true);
         break;
 
       case "WifiManager:forget:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:wps:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:wps:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:setPowerSavingMode:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:setPowerSavingMode:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:setHttpProxy:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:setHttpProxy:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:setStaticIpMode:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:setStaticIpMode:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:wifiDown":
         this._enabled = false;
@@ -215,32 +249,29 @@ DOMWifiManager.prototype = {
 
       case "WifiManager:wifiUp":
         this._enabled = true;
         this._macAddress = msg.macAddress;
         this._fireEnabledOrDisabled(true);
         break;
 
       case "WifiManager:onconnecting":
-        this._currentNetwork = msg.network;
-        exposeCurrentNetwork(this._currentNetwork);
+        this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "connecting";
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:onassociate":
-        this._currentNetwork = msg.network;
-        exposeCurrentNetwork(this._currentNetwork);
+        this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "associated";
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:onconnect":
-        this._currentNetwork = msg.network;
-        exposeCurrentNetwork(this._currentNetwork);
+        this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "connected";
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:ondisconnect":
         this._currentNetwork = null;
         this._connectionStatus = "disconnected";
         this._lastConnectionInfo = null;
@@ -264,179 +295,138 @@ DOMWifiManager.prototype = {
       case "WifiManager:onwpsoverlap":
         this._currentNetwork = null;
         this._connectionStatus = "wps-overlapped";
         this._lastConnectionInfo = null;
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:connectionInfoUpdate":
-        this._lastConnectionInfo = msg;
+        this._lastConnectionInfo = this._convertConnectionInfo(msg);
         this._fireConnectionInfoUpdate(msg);
         break;
       case "WifiManager:onconnectingfailed":
         this._currentNetwork = null;
         this._connectionStatus = "connectingfailed";
         this._lastConnectionInfo = null;
         this._fireStatusChangeEvent();
         break;
     }
   },
 
   _fireStatusChangeEvent: function StatusChangeEvent() {
-    if (this._onStatusChange) {
-      debug("StatusChangeEvent");
-      var event = new this._window.MozWifiStatusChangeEvent("statusChangeEvent",
-                                                            { network: this._currentNetwork,
-                                                              status: this._connectionStatus
-                                                            });
-      this._onStatusChange.handleEvent(event);
-    }
+    var event = new this._window.MozWifiStatusChangeEvent("statuschange",
+                                                          { network: this._currentNetwork,
+                                                            status: this._connectionStatus
+                                                          });
+    this.__DOM_IMPL__.dispatchEvent(event);
   },
 
-  _fireConnectionInfoUpdate: function connectionInfoUpdate(info) {
-    if (this._onConnectionInfoUpdate) {
-      debug("ConnectionInfoEvent");
-      var evt = new this._window.MozWifiConnectionInfoEvent("connectionInfoEvent",
-                                                            { network: this._currentNetwork,
-                                                              signalStrength: info.signalStrength,
-                                                              relSignalStrength: info.relSignalStrength,
-                                                              linkSpeed: info.linkSpeed,
-                                                              ipAddress: info.ipAddress,
-                                                            });
-      this._onConnectionInfoUpdate.handleEvent(evt);
-    }
+  _fireConnectionInfoUpdate: function onConnectionInfoUpdate(info) {
+    var evt = new this._window.MozWifiConnectionInfoEvent("connectioninfoupdate",
+                                                          { network: this._currentNetwork,
+                                                            signalStrength: info.signalStrength,
+                                                            relSignalStrength: info.relSignalStrength,
+                                                            linkSpeed: info.linkSpeed,
+                                                            ipAddress: info.ipAddress,
+                                                          });
+    this.__DOM_IMPL__.dispatchEvent(evt);
   },
 
   _fireEnabledOrDisabled: function enabledDisabled(enabled) {
-    var handler = enabled ? this._onEnabled : this._onDisabled;
-    if (handler) {
-      var evt = new this._window.Event("WifiEnabled");
-      handler.handleEvent(evt);
-    }
+    var evt = new this._window.Event(enabled ? "enabled" : "disabled");
+    this.__DOM_IMPL__.dispatchEvent(evt);
   },
 
-  // nsIDOMWifiManager
-  getNetworks: function nsIDOMWifiManager_getNetworks() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  getNetworks: function getNetworks() {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:getNetworks", null, request);
     return request;
   },
 
-  getKnownNetworks: function nsIDOMWifiManager_getKnownNetworks() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  getKnownNetworks: function getKnownNetworks() {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:getKnownNetworks", null, request);
     return request;
   },
 
-  associate: function nsIDOMWifiManager_associate(network) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  associate: function associate(network) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:associate", network, request);
+    this._sendMessageForRequest("WifiManager:associate",
+                                this._convertWifiNetworkToJSON(network), request);
     return request;
   },
 
-  forget: function nsIDOMWifiManager_forget(network) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  forget: function forget(network) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:forget", network, request);
+    this._sendMessageForRequest("WifiManager:forget",
+                                this._convertWifiNetworkToJSON(network), request);
     return request;
   },
 
-  wps: function nsIDOMWifiManager_wps(detail) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  wps: function wps(detail) {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:wps", detail, request);
     return request;
   },
 
-  setPowerSavingMode: function nsIDOMWifiManager_setPowerSavingMode(enabled) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  setPowerSavingMode: function setPowerSavingMode(enabled) {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:setPowerSavingMode", enabled, request);
     return request;
   },
 
-  setHttpProxy: function nsIDOMWifiManager_setHttpProxy(network, info) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  setHttpProxy: function setHttpProxy(network, info) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:setHttpProxy", {network:network, info:info}, request);
+    this._sendMessageForRequest("WifiManager:setHttpProxy",
+                                { network: this._convertWifiNetworkToJSON(network), info:info}, request);
     return request;
   },
 
-  setStaticIpMode: function nsIDOMWifiManager_setStaticIpMode(network, info) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  setStaticIpMode: function setStaticIpMode(network, info) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:setStaticIpMode", {network: network,info: info}, request);
+    this._sendMessageForRequest("WifiManager:setStaticIpMode",
+                                { network: this._convertWifiNetworkToJSON(network), info: info}, request);
     return request;
   },
 
   get enabled() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._enabled;
   },
 
   get macAddress() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._macAddress;
   },
 
   get connection() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    return exposeReadOnly({ status: this._connectionStatus,
-                            network: this._currentNetwork });
+    let _connection = this._convertConnection({ status: this._connectionStatus,
+                                                network: this._currentNetwork,
+                                              });
+    return _connection;
   },
 
   get connectionInformation() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    return this._lastConnectionInfo
-           ? exposeReadOnly(this._lastConnectionInfo)
-           : null;
-  },
-
-  set onstatuschange(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onStatusChange = callback;
+    return this._lastConnectionInfo;
   },
 
-  set connectionInfoUpdate(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onConnectionInfoUpdate = callback;
+  defineEventHandlerGetterSetter: function(name) {
+    Object.defineProperty(this, name, {
+      get: function() {
+        return this.__DOM_IMPL__.getEventHandler(name);
+      },
+      set: function(handler) {
+        this.__DOM_IMPL__.setEventHandler(name, handler);
+      }
+    });
   },
-
-  set onenabled(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onEnabled = callback;
-  },
-
-  set ondisabled(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onDisabled = callback;
-  }
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMWifiManager]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
+  DOMWifiManager, MozWifiNetwork, MozWifiConnection, MozWifiConnectionInfo
+]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("-*- DOMWifiManager component: " + s + "\n");
   };
 } else {
   debug = function (s) {};
--- a/dom/wifi/DOMWifiManager.manifest
+++ b/dom/wifi/DOMWifiManager.manifest
@@ -1,4 +1,12 @@
 # DOMWifiManager.js
-component {2cf775a7-1837-410c-9e26-323c42e076da} DOMWifiManager.js
-contract @mozilla.org/wifimanager;1 {2cf775a7-1837-410c-9e26-323c42e076da}
-category JavaScript-navigator-property mozWifiManager @mozilla.org/wifimanager;1
+component {c9b5f09e-25d2-40ca-aef4-c4d13d93c706} DOMWifiManager.js
+contract @mozilla.org/wifimanager;1 {c9b5f09e-25d2-40ca-aef4-c4d13d93c706}
+
+component {c01fd751-43c0-460a-8b64-abf652ec7220} DOMWifiManager.js
+contract @mozilla.org/mozwifinetwork;1 {c01fd751-43c0-460a-8b64-abf652ec7220}
+
+component {23579da4-201b-4319-bd42-9b7f337343ac} DOMWifiManager.js
+contract @mozilla.org/mozwificonnection;1 {23579da4-201b-4319-bd42-9b7f337343ac}
+
+component {83670352-6ed4-4c35-8de9-402296a1959c} DOMWifiManager.js
+contract @mozilla.org/mozwificonnectioninfo;1 {83670352-6ed4-4c35-8de9-402296a1959c}
--- a/dom/wifi/nsIWifi.idl
+++ b/dom/wifi/nsIWifi.idl
@@ -53,168 +53,8 @@ interface nsIWifi : nsISupports
      * Returns the list of currently available networks as well as the list of
      * currently configured networks.
      *
      * On success a callback is notified with the list of networks.
      * On failure after 3 scan retry attempts a callback is notified of failure.
      */
     void getWifiScanResults(in nsIWifiScanResultsReady callback);
 };
-
-[scriptable, uuid(e5a72295-1c5f-4848-9cbb-f1d3785c16c1)]
-interface nsIDOMWifiManager : nsISupports
-{
-    /**
-     * Returns the list of currently available networks.
-     * onsuccess: We have obtained the current list of networks. request.value
-     *            is an object whose property names are SSIDs and values are
-     *            network objects.
-     * onerror: We were unable to obtain a list of property names.
-     */
-    nsIDOMDOMRequest getNetworks();
-
-    /**
-     * Returns the list of networks known to the system that will be
-     * automatically connected to if they're in range.
-     * onsuccess: request.value is an object whose property names are
-     *            SSIDs and values are network objects.
-     * onerror: We were unable to obtain a list of known networks.
-     */
-    nsIDOMDOMRequest getKnownNetworks();
-
-    /**
-     * Takes one of the networks returned from getNetworks and tries to
-     * connect to it.
-     * @param network A network object with information about the network,
-     *                such as the SSID, key management desired, etc.
-     * onsuccess: We have started attempting to associate with the network.
-     *            request.value is true.
-     * onerror: We were unable to select the network. This most likely means a
-     *          configuration error.
-     */
-    nsIDOMDOMRequest associate(in jsval network);
-
-    /**
-     * Given a network, removes it from the list of networks that we'll
-     * automatically connect to. In order to re-connect to the network, it is
-     * necessary to call associate on it.
-     * @param network A network object with the SSID of the network to remove.
-     * onsuccess: We have removed this network. If we were previously
-     *            connected to it, we have started reconnecting to the next
-     *            network in the list.
-     * onerror: We were unable to remove the network.
-     */
-    nsIDOMDOMRequest forget(in jsval network);
-
-    /**
-     * Wi-Fi Protected Setup functionality.
-     * @param detail WPS detail which has 'method' and 'pin' field.
-     *               The possible method field values are:
-     *                 - pbc: The Push Button Configuration.
-     *                 - pin: The PIN configuration.
-     *                 - cancel: Request to cancel WPS in progress.
-     *               If method field is 'pin', 'pin' field can exist and has
-     *               a PIN number.
-     *               If method field is 'pin', 'bssid' field can exist and has
-     *               a opposite BSSID.
-     * onsuccess: We have successfully started/canceled wps.
-     * onerror: We have failed to start/cancel wps.
-     */
-    nsIDOMDOMRequest wps(in jsval detail);
-
-    /**
-     * Turn on/off wifi power saving mode.
-     * @param enabled true or false.
-     * onsuccess: We have successfully turn on/off wifi power saving mode.
-     * onerror: We have failed to turn on/off wifi power saving mode.
-     */
-    nsIDOMDOMRequest setPowerSavingMode(in boolean enabled);
-
-    /**
-     * Given a network, configure using static IP instead of running DHCP
-     * @param network A network object with the SSID of the network to set static ip.
-     * @param info info should have following field:
-     *        - enabled True to enable static IP, false to use DHCP
-     *        - ipaddr configured static IP address
-     *        - proxy configured proxy server address
-     *        - maskLength configured mask length
-     *        - gateway configured gateway address
-     *        - dns1 configured first DNS server address
-     *        - dns2 configured seconf DNS server address
-     * onsuccess: We have successfully configure the static ip mode.
-     * onerror: We have failed to configure the static ip mode.
-     */
-    nsIDOMDOMRequest setStaticIpMode(in jsval network,
-                                     in jsval info);
-
-    /**
-     * Given a network, configure http proxy when using wifi.
-     * @param network A network object with the SSID of the network to set http proxy.
-     * @param info info should have following field:
-     *        - httpProxyHost ip address of http proxy.
-     *        - httpProxyPort port of http proxy, set 0 to use default port 8080.
-     *        set info to null to clear http proxy.
-     * onsuccess: We have successfully configure http proxy.
-     * onerror: We have failed to configure http proxy.
-     */
-    nsIDOMDOMRequest setHttpProxy(in jsval network,
-                                  in jsval info);
-
-    /**
-     * Returns whether or not wifi is currently enabled.
-     */
-    readonly attribute boolean enabled;
-
-    /**
-     * Returns the MAC address of the wifi adapter.
-     */
-    readonly attribute DOMString macAddress;
-
-    /**
-     * An non-null object containing the following information:
-     *  - status ("disconnected", "connecting", "associated", "connected")
-     *  - network
-     *
-     *  Note that the object returned is read only. Any changes required must
-     *  be done by calling other APIs.
-     */
-    readonly attribute jsval connection;
-
-    /**
-     * A connectionInformation object with the same information found in an
-     * nsIDOMMozWifiConnectionInfoEvent (but without the network).
-     * If we are not currently connected to a network, this will be null.
-     */
-    readonly attribute jsval connectionInformation;
-
-    /**
-     * State notification listeners. These all take an
-     * nsIDOMMozWifiStatusChangeEvent with the new status and a network (which
-     * may be null).
-     *
-     * The possible statuses are:
-     *   - connecting: Fires when we start the process of connecting to a
-     *                 network.
-     *   - associated: Fires when we have connected to an access point but do
-     *                 not yet have an IP address.
-     *   - connected: Fires once we are fully connected to an access point and
-     *                can access the internet.
-     *   - disconnected: Fires when we either fail to connect to an access
-     *                   point (transition: associated -> disconnected) or
-     *                   when we were connected to a network but have
-     *                   disconnected for any reason (transition: connected ->
-     *                   disconnected).
-     */
-    attribute nsIDOMEventListener onstatuschange;
-
-    /**
-     * An event listener that is called with information about the signal
-     * strength and link speed every 5 seconds.
-     */
-    attribute nsIDOMEventListener connectionInfoUpdate;
-
-    /**
-     * These two events fire when the wifi system is brought online or taken
-     * offline.
-     */
-    attribute nsIDOMEventListener onenabled;
-    attribute nsIDOMEventListener ondisabled;
-};
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -873,16 +873,18 @@ SetProcessPriority(int aPid,
 
 // From HalTypes.h.
 const char*
 ProcessPriorityToString(ProcessPriority aPriority)
 {
   switch (aPriority) {
   case PROCESS_PRIORITY_MASTER:
     return "MASTER";
+  case PROCESS_PRIORITY_PREALLOC:
+    return "PREALLOC";
   case PROCESS_PRIORITY_FOREGROUND_HIGH:
     return "FOREGROUND_HIGH";
   case PROCESS_PRIORITY_FOREGROUND:
     return "FOREGROUND";
   case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
     return "FOREGROUND_KEYBOARD";
   case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
     return "BACKGROUND_PERCEIVABLE";
@@ -911,16 +913,23 @@ ProcessPriorityToString(ProcessPriority 
   switch (aPriority) {
   case PROCESS_PRIORITY_MASTER:
     if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
       return "MASTER:CPU_NORMAL";
     }
     if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
       return "MASTER:CPU_LOW";
     }
+  case PROCESS_PRIORITY_PREALLOC:
+    if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
+      return "PREALLOC:CPU_NORMAL";
+    }
+    if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
+      return "PREALLOC:CPU_LOW";
+    }
   case PROCESS_PRIORITY_FOREGROUND_HIGH:
     if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
       return "FOREGROUND_HIGH:CPU_NORMAL";
     }
     if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
       return "FOREGROUND_HIGH:CPU_LOW";
     }
   case PROCESS_PRIORITY_FOREGROUND:
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -79,16 +79,19 @@ typedef Observer<SwitchEvent> SwitchObse
 // Note that we rely on the order of this enum's entries.  Higher priorities
 // should have larger int values.
 enum ProcessPriority {
   PROCESS_PRIORITY_UNKNOWN = -1,
   PROCESS_PRIORITY_BACKGROUND,
   PROCESS_PRIORITY_BACKGROUND_HOMESCREEN,
   PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE,
   PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
+  // The special class for the preallocated process, high memory priority but
+  // low CPU priority.
+  PROCESS_PRIORITY_PREALLOC,
   // Any priority greater than or equal to FOREGROUND is considered
   // "foreground" for the purposes of priority testing, for example
   // CurrentProcessIsForeground().
   PROCESS_PRIORITY_FOREGROUND,
   PROCESS_PRIORITY_FOREGROUND_HIGH,
   PROCESS_PRIORITY_MASTER,
   NUM_PROCESS_PRIORITY
 };
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -1251,16 +1251,19 @@ EnsureKernelLowMemKillerParamsSet()
       MOZ_CRASH();
     }
 
     int32_t killUnderKB;
     if (!NS_SUCCEEDED(Preferences::GetInt(
           nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB",
                           ProcessPriorityToString(priority)).get(),
           &killUnderKB))) {
+      // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
+      // which has only OomScoreAdjust but lacks KillUnderMB value, will not
+      // create new LMK parameters.
       continue;
     }
 
     // The LMK in kernel silently malfunctions if we assign the parameters
     // in non-increasing order, so we add this assertion here. See bug 887192.
     MOZ_ASSERT(oomScoreAdj > lowerBoundOfNextOomScoreAdj);
     MOZ_ASSERT(killUnderKB > lowerBoundOfNextKillUnderKB);
 
--- a/media/mtransport/gonk_addrs.cpp
+++ b/media/mtransport/gonk_addrs.cpp
@@ -36,17 +36,19 @@ GetInterfaces(std::vector<NetworkInterfa
   // Obtain network interfaces from network manager.
   nsresult rv;
   nsCOMPtr<nsINetworkInterfaceListService> listService =
     do_GetService("@mozilla.org/network/interface-list-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t flags =
     nsINetworkInterfaceListService::LIST_NOT_INCLUDE_SUPL_INTERFACES |
-    nsINetworkInterfaceListService::LIST_NOT_INCLUDE_MMS_INTERFACES;
+    nsINetworkInterfaceListService::LIST_NOT_INCLUDE_MMS_INTERFACES |
+    nsINetworkInterfaceListService::LIST_NOT_INCLUDE_IMS_INTERFACES |
+    nsINetworkInterfaceListService::LIST_NOT_INCLUDE_DUN_INTERFACES;
   nsCOMPtr<nsINetworkInterfaceList> networkList;
   NS_ENSURE_SUCCESS(listService->GetDataInterfaceList(flags,
                                                       getter_AddRefs(networkList)),
                     NS_ERROR_FAILURE);
 
   // Translate nsINetworkInterfaceList to NetworkInterface.
   int32_t listLength;
   NS_ENSURE_SUCCESS(networkList->GetNumberOfInterface(&listLength),
--- a/netwerk/mime/nsMimeTypes.h
+++ b/netwerk/mime/nsMimeTypes.h
@@ -74,16 +74,17 @@
 
 #define AUDIO_BASIC                         "audio/basic"
 #define AUDIO_OGG                           "audio/ogg"
 #define AUDIO_WAV                           "audio/x-wav"
 #define AUDIO_WEBM                          "audio/webm"
 #define AUDIO_MP3                           "audio/mpeg"
 #define AUDIO_MP4                           "audio/mp4"
 #define AUDIO_AMR                           "audio/amr"
+#define AUDIO_3GPP                          "audio/3gpp"
 #define AUDIO_MIDI                          "audio/x-midi"
 
 #define BINARY_OCTET_STREAM                 "binary/octet-stream"
 
 #define IMAGE_GIF                           "image/gif"
 #define IMAGE_JPEG                          "image/jpeg"
 #define IMAGE_JPG                           "image/jpg"
 #define IMAGE_PJPEG                         "image/pjpeg"
--- a/testing/marionette/client/marionette/emulator.py
+++ b/testing/marionette/client/marionette/emulator.py
@@ -220,16 +220,20 @@ class Emulator(object):
                 raise Exception('bad telnet response: %s' % line)
 
     def _run_telnet(self, command):
         if not self.telnet:
             self.telnet = Telnet('localhost', self.port)
             self._get_telnet_response()
         return self._get_telnet_response(command)
 
+    def _run_shell(self, args):
+        args.insert(0, 'shell')
+        return self._run_adb(args).split('\r\n')
+
     def close(self):
         if self.is_running and self._emulator_launched:
             self.proc.kill()
         if self._adb_started:
             self._run_adb(['kill-server'])
             self._adb_started = False
         if self.proc:
             retcode = self.proc.poll()
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -603,34 +603,52 @@ class Marionette(object):
             self.session = None
             self.window = None
             self.client.close()
             raise TimeoutException(
                 "Connection timed out", status=ErrorCodes.TIMEOUT)
 
         # Process any emulator commands that are sent from a script
         # while it's executing.
-        while response.get("emulator_cmd"):
-            response = self._handle_emulator_cmd(response)
+        while True:
+            if response.get("emulator_cmd"):
+                response = self._handle_emulator_cmd(response)
+                continue;
+
+            if response.get("emulator_shell"):
+                response = self._handle_emulator_shell(response)
+                continue;
+
+            break;
 
         if response_key in response:
             return response[response_key]
         self._handle_error(response)
 
     def _handle_emulator_cmd(self, response):
         cmd = response.get("emulator_cmd")
         if not cmd or not self.emulator:
             raise MarionetteException(
                 "No emulator in this test to run command against")
         cmd = cmd.encode("ascii")
         result = self.emulator._run_telnet(cmd)
         return self.client.send({"name": "emulatorCmdResult",
                                  "id": response.get("id"),
                                  "result": result})
 
+    def _handle_emulator_shell(self, response):
+        args = response.get("emulator_shell")
+        if not isinstance(args, list) or not self.emulator:
+            raise MarionetteException(
+                "No emulator in this test to run shell command against")
+        result = self.emulator._run_shell(args)
+        return self.client.send({"name": "emulatorCmdResult",
+                                 "id": response.get("id"),
+                                 "result": result})
+
     def _handle_error(self, response):
         if 'error' in response and isinstance(response['error'], dict):
             status = response['error'].get('status', 500)
             message = response['error'].get('message')
             stacktrace = response['error'].get('stacktrace')
             # status numbers come from
             # http://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes
             if status == ErrorCodes.NO_SUCH_ELEMENT:
--- a/testing/marionette/client/marionette/tests/unit/test_emulator.py
+++ b/testing/marionette/client/marionette/tests/unit/test_emulator.py
@@ -12,16 +12,24 @@ class TestEmulatorContent(MarionetteTest
         self.marionette.set_script_timeout(10000)
         expected = ["<build>",
                     "OK"]
         result = self.marionette.execute_async_script("""
         runEmulatorCmd("avd name", marionetteScriptFinished)
         """);
         self.assertEqual(result, expected)
 
+    def test_emulator_shell(self):
+        self.marionette.set_script_timeout(10000)
+        expected = ["Hello World!", ""]
+        result = self.marionette.execute_async_script("""
+        runEmulatorShell(["echo", "Hello World!"], marionetteScriptFinished)
+        """);
+        self.assertEqual(result, expected)
+
     def test_emulator_order(self):
         self.marionette.set_script_timeout(10000)
         self.assertRaises(MarionetteException,
                           self.marionette.execute_async_script,
         """runEmulatorCmd("gsm status", function(result) {});
            marionetteScriptFinished(true);
         """);
 
--- a/testing/marionette/marionette-frame-manager.js
+++ b/testing/marionette/marionette-frame-manager.js
@@ -158,16 +158,17 @@ FrameManager.prototype = {
   addMessageManagerListeners: function MDA_addMessageManagerListeners(messageManager) {
     messageManager.addWeakMessageListener("Marionette:ok", this.server);
     messageManager.addWeakMessageListener("Marionette:done", this.server);
     messageManager.addWeakMessageListener("Marionette:error", this.server);
     messageManager.addWeakMessageListener("Marionette:log", this.server);
     messageManager.addWeakMessageListener("Marionette:shareData", this.server);
     messageManager.addWeakMessageListener("Marionette:register", this.server);
     messageManager.addWeakMessageListener("Marionette:runEmulatorCmd", this.server);
+    messageManager.addWeakMessageListener("Marionette:runEmulatorShell", this.server);
     messageManager.addWeakMessageListener("Marionette:switchToModalOrigin", this.server);
     messageManager.addWeakMessageListener("Marionette:switchToFrame", this.server);
     messageManager.addWeakMessageListener("Marionette:switchedToFrame", this.server);
     messageManager.addWeakMessageListener("MarionetteFrame:handleModal", this);
     messageManager.addWeakMessageListener("MarionetteFrame:getInterruptedState", this);
   },
 
   /**
@@ -185,14 +186,15 @@ FrameManager.prototype = {
   removeMessageManagerListeners: function MDA_removeMessageManagerListeners(messageManager) {
     messageManager.removeWeakMessageListener("Marionette:ok", this.server);
     messageManager.removeWeakMessageListener("Marionette:done", this.server);
     messageManager.removeWeakMessageListener("Marionette:error", this.server);
     messageManager.removeWeakMessageListener("Marionette:log", this.server);
     messageManager.removeWeakMessageListener("Marionette:shareData", this.server);
     messageManager.removeWeakMessageListener("Marionette:register", this.server);
     messageManager.removeWeakMessageListener("Marionette:runEmulatorCmd", this.server);
+    messageManager.removeWeakMessageListener("Marionette:runEmulatorShell", this.server);
     messageManager.removeWeakMessageListener("Marionette:switchToFrame", this.server);
     messageManager.removeWeakMessageListener("Marionette:switchedToFrame", this.server);
     messageManager.removeWeakMessageListener("MarionetteFrame:handleModal", this);
   },
 
 };
--- a/testing/marionette/marionette-listener.js
+++ b/testing/marionette/marionette-listener.js
@@ -2014,16 +2014,24 @@ let _emu_cbs = {};
 function runEmulatorCmd(cmd, callback) {
   if (callback) {
     _emu_cbs[_emu_cb_id] = callback;
   }
   sendAsyncMessage("Marionette:runEmulatorCmd", {emulator_cmd: cmd, id: _emu_cb_id});
   _emu_cb_id += 1;
 }
 
+function runEmulatorShell(args, callback) {
+  if (callback) {
+    _emu_cbs[_emu_cb_id] = callback;
+  }
+  sendAsyncMessage("Marionette:runEmulatorShell", {emulator_shell: args, id: _emu_cb_id});
+  _emu_cb_id += 1;
+}
+
 function emulatorCmdResult(msg) {
   let message = msg.json;
   if (!sandbox) {
     return;
   }
   let cb = _emu_cbs[message.id];
   delete _emu_cbs[message.id];
   if (!cb) {
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -2123,16 +2123,27 @@ MarionetteServerConnection.prototype = {
         this._emu_cbs = {};
       }
       this._emu_cbs[this._emu_cb_id] = callback;
     }
     this.sendToClient({emulator_cmd: cmd, id: this._emu_cb_id}, -1);
     this._emu_cb_id += 1;
   },
 
+  runEmulatorShell: function runEmulatorShell(args, callback) {
+    if (callback) {
+      if (!this._emu_cbs) {
+        this._emu_cbs = {};
+      }
+      this._emu_cbs[this._emu_cb_id] = callback;
+    }
+    this.sendToClient({emulator_shell: args, id: this._emu_cb_id}, -1);
+    this._emu_cb_id += 1;
+  },
+
   emulatorCmdResult: function emulatorCmdResult(message) {
     if (this.context != "chrome") {
       this.sendAsync("emulatorCmdResult", message, -1);
       return;
     }
 
     if (!this._emu_cbs) {
       return;
@@ -2320,16 +2331,17 @@ MarionetteServerConnection.prototype = {
         break;
       case "Marionette:shareData":
         //log messages from tests
         if (message.json.log) {
           this.marionetteLog.addLogs(message.json.log);
         }
         break;
       case "Marionette:runEmulatorCmd":
+      case "Marionette:runEmulatorShell":
         this.sendToClient(message.json, -1);
         break;
       case "Marionette:switchToFrame":
         this.curBrowser.frameManager.switchToFrame(message);
         this.messageManager = this.curBrowser.frameManager.currentRemoteFrame.messageManager.get();
         break;
       case "Marionette:switchToModalOrigin":
         this.curBrowser.frameManager.switchToModalOrigin(message);
--- a/testing/marionette/marionette-simpletest.js
+++ b/testing/marionette/marionette-simpletest.js
@@ -17,17 +17,17 @@ this.Marionette = function Marionette(sc
   this.testName = testName;
   this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL";
   this.TEST_PASS = "TEST-PASS";
   this.TEST_KNOWN_FAIL = "TEST-KNOWN-FAIL";
 }
 
 Marionette.prototype = {
   exports: ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor',
-            'runEmulatorCmd', 'TEST_PASS', 'TEST_KNOWN_FAIL',
+            'runEmulatorCmd', 'runEmulatorShell', 'TEST_PASS', 'TEST_KNOWN_FAIL',
             'TEST_UNEXPECTED_FAIL'],
 
   ok: function Marionette__ok(condition, name, passString, failString, diag) {
     this.heartbeatCallback();
     if (typeof(diag) == "undefined") {
       diag = this.repr(condition) + " was " + !!condition + ", expected true";
     }
     let test = {'result': !!condition, 'name': name, 'diag': diag};
@@ -158,10 +158,15 @@ Marionette.prototype = {
       this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, deadline - now);
   },
 
   runEmulatorCmd: function runEmulatorCmd(cmd, callback) {
     this.heartbeatCallback();
     this.scope.runEmulatorCmd(cmd, callback);
   },
 
+  runEmulatorShell: function runEmulatorShell(args, callback) {
+    this.heartbeatCallback();
+    this.scope.runEmulatorShell(args, callback);
+  },
+
 };
 
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -39,19 +39,16 @@ SERV_FILES = 	\
 		browser-harness.xul \
 		redirect.html \
 		$(topsrcdir)/build/pgo/server-locations.txt \
 		$(topsrcdir)/netwerk/test/httpserver/httpd.js \
 		pywebsocket_wrapper.py \
 		android.json \
 		androidx86.json \
 		android23.json \
-		b2g.json \
-		b2g-desktop.json \
-		b2g-debug.json \
 		gl.json \
 		b2g_start_script.js \
 		$(NULL)	
 
 ifeq ($(MOZ_BUILD_APP),mobile/android)
 SERV_FILES += \
   $(topsrcdir)/mobile/android/base/tests/robocop.ini \
   $(topsrcdir)/mobile/android/base/tests/robocop_autophone.ini \
deleted file mode 100644
--- a/testing/mochitest/b2g-debug.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-"runtests": {
-  },
-"excludetests": {
-  }
-}
deleted file mode 100644
--- a/testing/mochitest/b2g-desktop.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-"runtests": {
-  },
-"excludetests": {
-  }
-}
deleted file mode 100644
--- a/testing/mochitest/b2g.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-"runtests": {
-  },
-"excludetests": {
-  }
-}
--- a/testing/mochitest/mach_commands.py
+++ b/testing/mochitest/mach_commands.py
@@ -138,23 +138,16 @@ class MochitestRunner(MozbuildObject):
             test_root_file = mozpack.path.join(self.mochitest_dir, 'tests', test_path)
             if not os.path.exists(test_root_file):
                 print('Specified test path does not exist: %s' % test_root_file)
                 return 1
             if os.path.isdir(test_root_file):
                 test_path_dir = True;
             options.testPath = test_path
 
-        # filter test directiories or all tests according to the manifest
-        if not test_path or test_path_dir:
-            if conditions.is_b2g_desktop(self):
-                options.testManifest = 'b2g-desktop.json'
-            else:
-                options.testManifest = 'b2g.json'
-
         for k, v in kwargs.iteritems():
             setattr(options, k, v)
         options.noWindow = no_window
         options.totalChunks = total_chunks
         options.thisChunk = this_chunk
 
         options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols')
 
--- a/widget/gonk/HwcComposer2D.h
+++ b/widget/gonk/HwcComposer2D.h
@@ -42,16 +42,33 @@ typedef hwc_composer_device_1_t HwcDevic
 typedef hwc_display_contents_1_t HwcList;
 typedef hwc_layer_1_t HwcLayer;
 #else
 typedef hwc_composer_device_t HwcDevice;
 typedef hwc_layer_list_t HwcList;
 typedef hwc_layer_t HwcLayer;
 #endif
 
+/*
+ * HwcComposer2D provides a way for gecko to render frames
+ * using hwcomposer.h in the AOSP HAL.
+ *
+ * hwcomposer.h defines an interface for display composition
+ * using dedicated hardware. This hardware is usually faster
+ * or more power efficient than the GPU. However, in exchange
+ * for better performance, generality has to be sacrificed:
+ * no 3d transforms, no intermediate surfaces, no special shader effects,
+ * and loss of other goodies depending on the platform.
+ *
+ * In general, when hwc is enabled gecko tries to compose
+ * its frames using HwcComposer2D first. Then if HwcComposer2D is
+ * unable to compose a frame then it falls back to compose it
+ * using the GPU with OpenGL.
+ *
+ */
 class HwcComposer2D : public mozilla::layers::Composer2D {
 public:
     HwcComposer2D();
     virtual ~HwcComposer2D();
 
     int Init(hwc_display_t aDisplay, hwc_surface_t aSurface);
 
     bool Initialized() const { return mHwc; }