Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 29 Sep 2012 12:32:07 -0400
changeset 108737 879cce846c1e5f6d81f5889cfedbd39c2f143372
parent 108695 1f7dbc3b3bafca41cafaddc27955eeab69bc7b6b (current diff)
parent 108736 1d3de8da2508e3acdaa3ddf1e0769472d3704f0b (diff)
child 108738 cd82278e2bb8f4a297833c50c69c47b80d717d55
child 108743 a34cf400a83cd7733a194928107735de687cf655
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
milestone18.0a1
Merge the last PGO-green inbound changeset to m-c.
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -549,18 +549,27 @@ pref("dom.ipc.processPrelauch.delayMs", 
 
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
 
 // Screen reader support
 pref("accessibility.accessfu.activate", 2);
 
 // Enable hit-target fluffing
-pref("ui.touch.radius.enabled", true);
-pref("ui.mouse.radius.enabled", true);
+pref("ui.touch.radius.enabled", false);
+pref("ui.touch.radius.leftmm", 3);
+pref("ui.touch.radius.topmm", 5);
+pref("ui.touch.radius.rightmm", 3);
+pref("ui.touch.radius.bottommm", 2);
+
+pref("ui.mouse.radius.enabled", false);
+pref("ui.mouse.radius.leftmm", 3);
+pref("ui.mouse.radius.topmm", 5);
+pref("ui.mouse.radius.rightmm", 3);
+pref("ui.mouse.radius.bottommm", 2);
 
 // Disable native prompt
 pref("browser.prompt.allowNative", false);
 
 // Minimum delay in milliseconds between network activity notifications (0 means
 // no notifications). The delay is the same for both download and upload, though
 // they are handled separately. This pref is only read once at startup:
 // a restart is required to enable a new value.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -728,17 +728,17 @@ const gFormSubmitObserver = {
                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
 
       if (style.direction == 'rtl') {
         offset = parseInt(style.paddingRight) + parseInt(style.borderRightWidth);
       } else {
         offset = parseInt(style.paddingLeft) + parseInt(style.borderLeftWidth);
       }
 
-      offset = Math.round(offset * utils.screenPixelsPerCSSPixel);
+      offset = Math.round(offset * utils.fullZoom);
 
       position = "after_start";
     }
 
     this.panel.openPopup(element, position, offset, 0);
   }
 };
 
@@ -7546,19 +7546,19 @@ var MousePosTracker = {
     var index = this._listeners.indexOf(listener);
     if (index < 0)
       return;
 
     this._listeners.splice(index, 1);
   },
 
   handleEvent: function (event) {
-    var screenPixelsPerCSSPixel = this._windowUtils.screenPixelsPerCSSPixel;
-    this._x = event.screenX / screenPixelsPerCSSPixel - window.mozInnerScreenX;
-    this._y = event.screenY / screenPixelsPerCSSPixel - window.mozInnerScreenY;
+    var fullZoom = this._windowUtils.fullZoom;
+    this._x = event.screenX / fullZoom - window.mozInnerScreenX;
+    this._y = event.screenY / fullZoom - window.mozInnerScreenY;
 
     this._listeners.forEach(function (listener) {
       try {
         this._callListener(listener);
       } catch (e) {
         Cu.reportError(e);
       }
     }, this);
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3572,22 +3572,27 @@
         // otherwise trying to deatch the tab by dropping it on the desktop
         // may result in an "internet shortcut"
         dt.mozSetDataAt("text/x-moz-text-internal", browser.currentURI.spec, 0);
 
         // Set the cursor to an arrow during tab drags.
         dt.mozCursor = "default";
 
         // Create a canvas to which we capture the current tab.
+        // Until canvas is HiDPI-aware (bug 780362), we need to scale the desired
+        // canvas size (in CSS pixels) to the window's backing resolution in order
+        // to get a full-resolution drag image for use on HiDPI displays.
+        let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils);
+        let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom;
         let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
         canvas.mozOpaque = true;
-        canvas.width = 160;
-        canvas.height = 90;
+        canvas.width = 160 * scale;
+        canvas.height = 90 * scale;
         PageThumbs.captureToCanvas(browser.contentWindow, canvas);
-        dt.setDragImage(canvas, -16, -16);
+        dt.setDragImage(canvas, -16 * scale, -16 * scale);
 
         // _dragData.offsetX/Y give the coordinates that the mouse should be
         // positioned relative to the corner of the new window created upon
         // dragend such that the mouse appears to have the same position
         // relative to the corner of the dragged tab.
         function clientX(ele) ele.getBoundingClientRect().left;
         let tabOffsetX = clientX(tab) - clientX(this);
         tab._dragData = {
--- a/browser/devtools/highlighter/highlighter.jsm
+++ b/browser/devtools/highlighter/highlighter.jsm
@@ -689,17 +689,17 @@ Highlighter.prototype = {
 
   /**
    * Store page zoom factor.
    */
   computeZoomFactor: function Highlighter_computeZoomFactor() {
     this.zoom =
       this.win.QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIDOMWindowUtils)
-      .screenPixelsPerCSSPixel;
+      .fullZoom;
   },
 
   /////////////////////////////////////////////////////////////////////////
   //// Event Emitter Mechanism
 
   addListener: function Highlighter_addListener(aEvent, aListener)
   {
     if (!(aEvent in this.events))
--- a/browser/devtools/shared/LayoutHelpers.jsm
+++ b/browser/devtools/shared/LayoutHelpers.jsm
@@ -170,17 +170,17 @@ LayoutHelpers = {
   /**
    * Apply the page zoom factor.
    */
   getZoomedRect: function LH_getZoomedRect(aWin, aRect) {
     // get page zoom factor, if any
     let zoom =
       aWin.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
         .getInterface(Components.interfaces.nsIDOMWindowUtils)
-        .screenPixelsPerCSSPixel;
+        .fullZoom;
 
     // adjust rect for zoom scaling
     let aRectScaled = {};
     for (let prop in aRect) {
       aRectScaled[prop] = aRect[prop] * zoom;
     }
 
     return aRectScaled;
--- a/browser/locales/en-US/searchplugins/google.xml
+++ b/browser/locales/en-US/searchplugins/google.xml
@@ -11,17 +11,17 @@
 #define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-nightly" falseValue="firefox"/>
 #else
 #define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
 #endif
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Google</ShortName>
 <Description>Google Search</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
+<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABUUlEQVR42pWTzUsCYRCH9y9zu3SooCCkjhIRRLeIykXokiWCJ7PvDpZRlz6si1lIQZ3SQxQdOhREpgSm0JeQvfu0+i6I7LKLh4F5h5nnnRl+o6jTdHn8omAYbVqhXqvYFXcEBKFDwcoZZB8B4LkEB9cwGGmFKHb01A1EU9JXzfdvDYZi1lwLwBcVAIwsNWPesIwls7gDtB2Z7N9ujVe+IX2LO2AgItB1OL9vJqsmILDrOoK02IkBAdYy4FsQJC5h+VQCHQDWTqYSgo8fuHuRxS4Ae3stQ7UGE5ttAHqCUgfxC7m4ryrowOyeO6CxqHwZxtYFqtYc5+kNan/gDTsAeueEIRj7n/rmRQMwueUAGF0VAAT3rQBTC0Y3DoDOGbm00icML4oWHYSTgo0MFqjlmPpDgqMcFCuQf4erBzjOwXjcriu9qHg0uutO2+es6fl67T9ptebvFRjBVgAAAABJRU5ErkJggg==</Image>
 <Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&amp;q={searchTerms}"/>
 <Url type="text/html" method="GET" template="https://www.google.com/search">
 #expand   __GOOGLE_PARAMS__
 #expand   __GOOGLE_CLIENT_PARAM__
 </Url>
 <!-- Keyword search URL is the same as the default, but with an additional parameter -->
 <Url type="application/x-moz-keywordsearch" method="GET" template="https://www.google.com/search">
 #expand   __GOOGLE_PARAMS__
--- a/build/autoconf/android.m4
+++ b/build/autoconf/android.m4
@@ -173,16 +173,18 @@ if test "$OS_TARGET" = "Android" -a -z "
     x86-*)
         ANDROID_CPU_ARCH=x86
         ;;
     mips-*) # When target_cpu is mipsel, CPU_ARCH is mips
         ANDROID_CPU_ARCH=mips
         ;;
     esac
 
+    AC_SUBST(ANDROID_CPU_ARCH)
+
     if test -z "$STLPORT_CPPFLAGS$STLPORT_LDFLAGS$STLPORT_LIBS"; then
         if test -e "$android_ndk/sources/cxx-stl/stlport/src/iostream.cpp" ; then
             if test -e "$android_ndk/sources/cxx-stl/stlport/libs/$ANDROID_CPU_ARCH/libstlport_static.a"; then
                 STLPORT_LDFLAGS="-L$_objdir/build/stlport -L$android_ndk/sources/cxx-stl/stlport/libs/$ANDROID_CPU_ARCH/"
             elif test -e "$android_ndk/tmp/ndk-digit/build/install/sources/cxx-stl/stlport/libs/$ANDROID_CPU_ARCH/libstlport_static.a"; then
                 STLPORT_LDFLAGS="-L$_objdir/build/stlport -L$android_ndk/tmp/ndk-digit/build/install/sources/cxx-stl/stlport/libs/$ANDROID_CPU_ARCH/"
             else
                 AC_MSG_ERROR([Couldn't find path to stlport in the android ndk])
--- a/configure.in
+++ b/configure.in
@@ -1,8 +1,9 @@
+
 dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*-
 dnl vi: set tabstop=4 shiftwidth=4 expandtab syntax=m4:
 dnl This Source Code Form is subject to the terms of the Mozilla Public
 dnl License, v. 2.0. If a copy of the MPL was not distributed with this
 dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 dnl Process this file with autoconf to produce a configure script.
 dnl ========================================================
@@ -192,17 +193,17 @@ if test -n "$gonkdir" ; then
     arm)
         ARCH_DIR=arch-arm
         ;;
     i?86)
         ARCH_DIR=arch-x86
         ;;
     esac
 
-    CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice -I$gonkdir/frameworks/base/services/camera -I$gonkdir/system/media/wilhelm/include"
+    CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice -I$gonkdir/frameworks/base/services/camera -I$gonkdir/system/media/wilhelm/include -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/dalvik/libnativehelper/include/nativehelper"
     CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
     CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions -Wno-psabi $CXXFLAGS $STLPORT_CPPFLAGS"
     dnl Add -llog by default, since we use it all over the place.
     LIBS="$LIBS -llog $STLPORT_LIBS"
 
     LDFLAGS="-mandroid -L$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib -Wl,-rpath-link=$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib --sysroot=$gonkdir/out/target/product/$GONK_PRODUCT/obj/ $LDFLAGS"
 
     dnl prevent cross compile section from using these flags as host flags
--- a/content/events/test/test_bug574663.html
+++ b/content/events/test/test_bug574663.html
@@ -57,32 +57,32 @@ function runTest() {
         win.close();
         clearPrefs();
         SimpleTest.finish();
         return;
       }
 
       let [ctrlKey, isMomentum] = outstandingTests.shift();
       let scrollTopBefore = scrollbox.scrollTop;
-      let zoomFactorBefore = winUtils.screenPixelsPerCSSPixel;
+      let zoomFactorBefore = winUtils.fullZoom;
       sendTouchpadScrollMotion(scrollbox, 1, ctrlKey, isMomentum);
 
       setTimeout(function () {
         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
         if (!ctrlKey) {
           let postfix = isMomentum ? ", even after releasing the touchpad" : "";
           // Normal scroll: scroll
-          is(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Normal scrolling shouldn't change zoom" + postfix);
+          is(winUtils.fullZoom, zoomFactorBefore, "Normal scrolling shouldn't change zoom" + postfix);
           isnot(scrollbox.scrollTop, scrollTopBefore, "Normal scrolling should scroll" + postfix);
         } else {
           if (!isMomentum) {
-            isnot(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Ctrl-scrolling should zoom while the user is touching the touchpad");
+            isnot(winUtils.fullZoom, zoomFactorBefore, "Ctrl-scrolling should zoom while the user is touching the touchpad");
             is(scrollbox.scrollTop, scrollTopBefore, "Ctrl-scrolling shouldn't scroll while the user is touching the touchpad");
           } else {
-            is(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Momentum scrolling shouldn't zoom, even when pressing Ctrl");
+            is(winUtils.fullZoom, zoomFactorBefore, "Momentum scrolling shouldn't zoom, even when pressing Ctrl");
             isnot(scrollbox.scrollTop, scrollTopBefore, "Momentum scrolling should scroll, even when pressing Ctrl");
           }
         }
         // Revert the effect.
         sendTouchpadScrollMotion(scrollbox, -1, ctrlKey, isMomentum);
         setTimeout(nextTest, 20);
       }, 20);
     }
--- a/content/svg/content/src/nsSVGDataParser.cpp
+++ b/content/svg/content/src/nsSVGDataParser.cpp
@@ -93,46 +93,16 @@ void nsSVGDataParser::GetNextToken()
 void nsSVGDataParser::RewindTo(const char* aPos)
 {
   mInputPos = aPos;
   GetNextToken();
 }
 
 //----------------------------------------------------------------------
 
-nsresult nsSVGDataParser::MatchNonNegativeNumber(float* aX)
-{
-  // XXX inefficient implementation. We probably hit the RewindTo case
-  // often.
-  
-  const char* pos = mTokenPos;
-
-  nsresult rv = MatchFloatingPointConst();
-
-  if (NS_FAILED(rv)) {
-    RewindTo(pos);
-    ENSURE_MATCHED(MatchIntegerConst());
-  }
-
-  char* end;
-  *aX = float(PR_strtod(pos, &end));
-  if (pos != end && NS_finite(*aX)) {
-    return NS_OK;
-  }
-  
-  return NS_ERROR_FAILURE;
-}
-
-bool nsSVGDataParser::IsTokenNonNegativeNumberStarter()
-{
-  return (mTokenType == DIGIT || mTokenType == POINT);
-}
-
-//----------------------------------------------------------------------
-
 nsresult nsSVGDataParser::MatchNumber(float* aX)
 {
   const char* pos = mTokenPos;
   
   if (mTokenType == SIGN)
     GetNextToken();
 
   const char* pos2 = mTokenPos;
--- a/content/svg/content/src/nsSVGDataParser.h
+++ b/content/svg/content/src/nsSVGDataParser.h
@@ -29,19 +29,16 @@ protected:
   enum { DIGIT, WSP, COMMA, POINT, SIGN, LEFT_PAREN, RIGHT_PAREN, OTHER, END } mTokenType;
   char mTokenVal;
 
   // helpers
   void GetNextToken();
   void RewindTo(const char* aPos);
   virtual nsresult Match()=0;
 
-  nsresult MatchNonNegativeNumber(float* aX);
-  bool IsTokenNonNegativeNumberStarter();
-  
   nsresult MatchNumber(float* x);
   bool IsTokenNumberStarter();
   
   nsresult MatchCommaWsp();
   bool IsTokenCommaWspStarter();
   
   nsresult MatchIntegerConst();
   
--- a/content/svg/content/src/nsSVGPathDataParser.cpp
+++ b/content/svg/content/src/nsSVGPathDataParser.cpp
@@ -784,23 +784,23 @@ nsresult nsSVGPathDataParser::MatchEllip
   
   return NS_OK;        
 }
 
 nsresult nsSVGPathDataParser::MatchEllipticalArcArg(float* x, float* y,
                                                     float* r1, float* r2, float* angle,
                                                     bool* largeArcFlag, bool* sweepFlag)
 {
-  ENSURE_MATCHED(MatchNonNegativeNumber(r1));
+  ENSURE_MATCHED(MatchNumber(r1));
 
   if (IsTokenCommaWspStarter()) {
     ENSURE_MATCHED(MatchCommaWsp());
   }
 
-  ENSURE_MATCHED(MatchNonNegativeNumber(r2));
+  ENSURE_MATCHED(MatchNumber(r2));
 
   if (IsTokenCommaWspStarter()) {
     ENSURE_MATCHED(MatchCommaWsp());
   }
 
   ENSURE_MATCHED(MatchNumber(angle));
 
   if (IsTokenCommaWspStarter()) {
@@ -822,17 +822,17 @@ nsresult nsSVGPathDataParser::MatchEllip
   ENSURE_MATCHED(MatchCoordPair(x, y));
   
   return NS_OK;  
   
 }
 
 bool nsSVGPathDataParser::IsTokenEllipticalArcArgStarter()
 {
-  return IsTokenNonNegativeNumberStarter();
+  return IsTokenNumberStarter();
 }
 
 
 //-----------------------------------------------------------------------
 
 
 
 
--- a/docshell/test/file_bug590573_1.html
+++ b/docshell/test/file_bug590573_1.html
@@ -1,8 +1,8 @@
 <html>
 <body onpopstate='opener.page1Popstate();' onload='opener.page1Load();'
       onpageshow='opener.page1PageShow();'>
 
-<div style='height:300%' id='div1'>This is a very tall div.</div>
+<div style='height:10000px' id='div1'>This is a very tall div.</div>
 
 </body>
 </html>
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1506,16 +1506,35 @@ NS_IMETHODIMP
 nsDOMWindowUtils::GetScreenPixelsPerCSSPixel(float* aScreenPixels)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   return window->GetDevicePixelRatio(aScreenPixels);
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GetFullZoom(float* aFullZoom)
+{
+  *aFullZoom = 1.0f;
+
+  if (!nsContentUtils::IsCallerTrustedForRead()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  nsPresContext* presContext = GetPresContext();
+  if (!presContext) {
+    return NS_OK;
+  }
+
+  *aFullZoom = presContext->DeviceContext()->GetPixelScale();
+
+  return NS_OK;
+}
+ 
+NS_IMETHODIMP
 nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
                                                nsIDOMEvent* aEvent,
                                                bool aTrusted,
                                                bool* aRetVal)
 {
   if (!nsContentUtils::IsCallerTrustedForRead()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -3,33 +3,34 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothPropertyEvent.h"
+#include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
-#include "BluetoothReplyRunnable.h"
+#include "BluetoothServiceUuid.h"
 #include "BluetoothUtils.h"
 #include "GeneratedEvents.h"
 
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
+#include "nsIDOMBluetoothDeviceAddressEvent.h"
 #include "nsIDOMBluetoothDeviceEvent.h"
-#include "nsIDOMBluetoothDeviceAddressEvent.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
-#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
@@ -720,16 +721,118 @@ BluetoothAdapter::SetAuthorization(const
     NS_WARNING("SetAuthorization failed!");
     return NS_ERROR_FAILURE;
   }
 
   req.forget(aRequest);
   return NS_OK;  
 }
 
+NS_IMETHODIMP
+BluetoothAdapter::Connect(const nsAString& aDeviceAddress,
+                          uint16_t aProfileId,
+                          nsIDOMDOMRequest** aRequest)
+{
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOMRequest!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<BluetoothVoidReplyRunnable> result = new BluetoothVoidReplyRunnable(req);
+
+  if (aProfileId == (uint16_t)(BluetoothServiceUuid::Handsfree >> 32)) {
+    if (!bs->ConnectHeadset(aDeviceAddress, mPath, result)) {
+      NS_WARNING("Creating RFCOMM socket failed.");
+      return NS_ERROR_FAILURE;
+    }
+  } else if (aProfileId == (uint16_t)(BluetoothServiceUuid::ObjectPush >> 32)) {
+    if (!bs->ConnectObjectPush(aDeviceAddress, mPath, result)) {
+      NS_WARNING("Creating RFCOMM socket failed");
+      return NS_ERROR_FAILURE;
+    }
+  } else {
+    NS_WARNING("Unknown profile");
+    return NS_ERROR_FAILURE;
+  }
+
+  req.forget(aRequest);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::Disconnect(uint16_t aProfileId,
+                             nsIDOMDOMRequest** aRequest)
+{
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOMRequest!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<BluetoothVoidReplyRunnable> result = new BluetoothVoidReplyRunnable(req);
+
+  if (aProfileId == (uint16_t)(BluetoothServiceUuid::Handsfree >> 32)) {
+    bs->DisconnectHeadset(result);
+  } else if (aProfileId == (uint16_t)(BluetoothServiceUuid::ObjectPush >> 32)) {
+    bs->DisconnectObjectPush(result);
+  } else {
+    NS_WARNING("Unknown profile");
+    return NS_ERROR_FAILURE;
+  }
+
+  req.forget(aRequest);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
+                           nsIDOMBlob* aBlob,
+                           nsIDOMDOMRequest** aRequest)
+{
+  // Will implement in another patch
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress,
+                                  nsIDOMDOMRequest** aRequest)
+{
+  // Will implement in another patch
+  return NS_OK;
+}
+
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, propertychanged)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicefound)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicedisappeared)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicecreated)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, requestconfirmation)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, requestpincode)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, requestpasskey)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, authorize)
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -1,18 +1,20 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "base/basictypes.h"
+#include "base/basictypes.h" 
+
 #include "BluetoothHfpManager.h"
 
 #include "BluetoothReplyRunnable.h"
+#include "BluetoothScoManager.h"
 #include "BluetoothService.h"
 #include "BluetoothServiceUuid.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsIRadioInterfaceLayer.h"
@@ -52,16 +54,47 @@ public:
 
       usleep(kRingInterval);
     }
 
     return NS_OK;
   }
 };
 
+void
+OpenScoSocket(const nsAString& aDevicePath)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  BluetoothScoManager* sco = BluetoothScoManager::Get();
+  if (!sco) {
+    NS_WARNING("BluetoothScoManager is not available!");
+    return;
+  }
+
+  if (!sco->Connect(aDevicePath)) {
+    NS_WARNING("Failed to create a sco socket!");
+  }
+}
+
+void
+CloseScoSocket()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  BluetoothScoManager* sco = BluetoothScoManager::Get();
+  if (!sco) {
+    NS_WARNING("BluetoothScoManager is not available!");
+    return;
+  }
+
+  if (sco->GetConnected())
+    sco->Disconnect();
+}
+
 BluetoothHfpManager::BluetoothHfpManager()
   : mCurrentVgs(-1)
   , mCurrentCallIndex(0)
   , mCurrentCallState(nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED)
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
 
   if (obs && NS_FAILED(obs->AddObserver(sInstance, MOZSETTINGS_CHANGED_ID, false))) {
@@ -350,16 +383,17 @@ BluetoothHfpManager::Connect(const nsASt
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     NS_WARNING("BluetoothService not available!");
     return false;
   }
+  mDevicePath = aDeviceObjectPath;
 
   nsString serviceUuidStr =
     NS_ConvertUTF8toUTF16(mozilla::dom::bluetooth::BluetoothServiceUuidStr::Handsfree);
 
   nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
 
   nsresult rv = bs->GetSocketViaService(aDeviceObjectPath,
                                         serviceUuidStr,
@@ -442,17 +476,17 @@ BluetoothHfpManager::CallStateChanged(in
           SendLine("+CIEV: 5,0");
           break;
         default:
 #ifdef DEBUG
           NS_WARNING("Not handling state changed");
 #endif
           break;
       }
-
+      OpenScoSocket(mDevicePath);
       break;
     case nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED:
       switch (mCurrentCallState) {
         case nsIRadioInterfaceLayer::CALL_STATE_INCOMING:
           sStopSendingRingFlag = true;
           // Continue executing, no break
         case nsIRadioInterfaceLayer::CALL_STATE_DIALING:
         case nsIRadioInterfaceLayer::CALL_STATE_ALERTING:
@@ -464,16 +498,17 @@ BluetoothHfpManager::CallStateChanged(in
           SendLine("+CIEV: 4,0");
           break;
         default:
 #ifdef DEBUG
           NS_WARNING("Not handling state changed");
 #endif
           break;
       }
+      CloseScoSocket();
       break;
 
     default:
 #ifdef DEBUG
       NS_WARNING("Not handling state changed");
 #endif
       break;
   }
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -41,13 +41,14 @@ private:
   bool BroadcastSystemMessage(const char* aCommand,
                               const int aCommandLength);
   nsresult HandleVolumeChanged(const nsAString& aData);
 
   int mCurrentVgs;
   int mCurrentCallIndex;
   int mCurrentCallState;
   nsAutoPtr<BluetoothRilListener> mListener;
+  nsString mDevicePath;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothScoManager.cpp
@@ -0,0 +1,113 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+
+#include "BluetoothScoManager.h"
+
+#include "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
+#include "BluetoothServiceUuid.h"
+
+#include "mozilla/Services.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "nsContentUtils.h"
+#include "nsIDOMDOMRequest.h"
+#include "nsIObserverService.h"
+#include "nsISystemMessagesInternal.h"
+#include "nsVariant.h"
+
+USING_BLUETOOTH_NAMESPACE
+using namespace mozilla::ipc;
+
+static nsRefPtr<BluetoothScoManager> sInstance;
+static nsCOMPtr<nsIThread> sScoCommandThread;
+
+BluetoothScoManager::BluetoothScoManager()
+{
+  if (!sScoCommandThread) {
+    if (NS_FAILED(NS_NewThread(getter_AddRefs(sScoCommandThread)))) {
+      NS_ERROR("Failed to new thread for sScoCommandThread");
+    }
+  }
+  mConnected = false;
+}
+
+BluetoothScoManager::~BluetoothScoManager()
+{
+  // Shut down the command thread if it still exists.
+  if (sScoCommandThread) {
+    nsCOMPtr<nsIThread> thread;
+    sScoCommandThread.swap(thread);
+    if (NS_FAILED(thread->Shutdown())) {
+      NS_WARNING("Failed to shut down the bluetooth hfpmanager command thread!");
+    }
+  }
+}
+
+//static
+BluetoothScoManager*
+BluetoothScoManager::Get()
+{
+  if (sInstance == nullptr) {
+    sInstance = new BluetoothScoManager();
+  }
+
+  // TODO: destroy pointer sInstance on shutdown
+  return sInstance;
+}
+
+// Virtual function of class SocketConsumer
+void
+BluetoothScoManager::ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage)
+{
+  // SCO socket do nothing here
+  MOZ_NOT_REACHED("This should never be called!");
+}
+
+bool
+BluetoothScoManager::Connect(const nsAString& aDeviceObjectPath)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mConnected) {
+    NS_WARNING("Sco socket has been ready");
+    return true;
+  }
+
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return false;
+  }
+
+  nsresult rv = bs->GetScoSocket(aDeviceObjectPath,
+                                 true,
+                                 false,
+                                 this);
+
+  return NS_FAILED(rv) ? false : true;
+}
+
+void
+BluetoothScoManager::Disconnect()
+{
+  CloseSocket();
+  mConnected = false;
+}
+
+// FIXME: detect connection in UnixSocketConsumer
+bool
+BluetoothScoManager::GetConnected()
+{
+  return mConnected;
+}
+
+void
+BluetoothScoManager::SetConnected(bool aConnected)
+{
+  mConnected = aConnected;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothScoManager.h
@@ -0,0 +1,38 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothscomanager_h__
+#define mozilla_dom_bluetooth_bluetoothscomanager_h__
+
+#include "BluetoothCommon.h"
+#include "mozilla/ipc/UnixSocket.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothReplyRunnable;
+
+class BluetoothScoManager : public mozilla::ipc::UnixSocketConsumer
+{
+public:
+  ~BluetoothScoManager();
+
+  static BluetoothScoManager* Get();
+  void ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage);
+
+  bool Connect(const nsAString& aDeviceObjectPath);
+  void Disconnect();
+  void SetConnected(bool aConnected);
+  bool GetConnected();
+
+private:
+  BluetoothScoManager();
+  void CreateScoSocket(const nsAString& aDevicePath);
+  bool mConnected;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -225,16 +225,22 @@ public:
                              BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual nsresult
   RemoveDeviceInternal(const nsAString& aAdapterPath,
                        const nsAString& aObjectPath,
                        BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual nsresult
+  GetScoSocket(const nsAString& aObjectPath,
+               bool aAuth,
+               bool aEncrypt,
+               mozilla::ipc::UnixSocketConsumer* aConsumer) = 0;
+
+  virtual nsresult
   GetSocketViaService(const nsAString& aObjectPath,
                       const nsAString& aService,
                       BluetoothSocketType aType,
                       bool aAuth,
                       bool aEncrypt,
                       mozilla::ipc::UnixSocketConsumer* aSocketConsumer,
                       BluetoothReplyRunnable* aRunnable) = 0;
 
@@ -252,16 +258,32 @@ public:
 
   virtual bool
   SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow,
                            BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual nsresult
   PrepareAdapterInternal(const nsAString& aPath) = 0;
 
+  virtual bool
+  ConnectHeadset(const nsAString& aDeviceAddress,
+                 const nsAString& aAdapterPath,
+                 BluetoothReplyRunnable* aRunnable) = 0;
+
+  virtual void
+  DisconnectHeadset(BluetoothReplyRunnable* aRunnable) = 0;
+
+  virtual bool
+  ConnectObjectPush(const nsAString& aDeviceAddress,
+                    const nsAString& aAdapterPath,
+                    BluetoothReplyRunnable* aRunnable) = 0;
+
+  virtual void
+  DisconnectObjectPush(BluetoothReplyRunnable* aRunnable) = 0;
+
   bool
   IsEnabled() const
   {
     return mEnabled;
   }
 
 protected:
   BluetoothService()
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -50,16 +50,17 @@ CPPSRCS += \
   BluetoothUtils.cpp \
   BluetoothChild.cpp \
   BluetoothParent.cpp \
   BluetoothServiceChildProcess.cpp \
   BluetoothUnixSocketConnector.cpp \
   BluetoothHfpManager.cpp \
   BluetoothOppManager.cpp \
   ObexBase.cpp \
+  BluetoothScoManager.cpp \
   $(NULL)
 
 ifdef MOZ_B2G_RIL
 CPPSRCS += BluetoothRilListener.cpp
 endif
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
--- a/dom/bluetooth/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -208,16 +208,24 @@ BluetoothParent::RecvPBluetoothRequestCo
     case Request::TConfirmPairingConfirmationRequest:
       return actor->DoRequest(aRequest.get_ConfirmPairingConfirmationRequest());
     case Request::TConfirmAuthorizationRequest:
       return actor->DoRequest(aRequest.get_ConfirmAuthorizationRequest());
     case Request::TDenyPairingConfirmationRequest:
       return actor->DoRequest(aRequest.get_DenyPairingConfirmationRequest());
     case Request::TDenyAuthorizationRequest:
       return actor->DoRequest(aRequest.get_DenyAuthorizationRequest());
+    case Request::TConnectHeadsetRequest:
+      return actor->DoRequest(aRequest.get_ConnectHeadsetRequest());
+    case Request::TConnectObjectPushRequest:
+      return actor->DoRequest(aRequest.get_ConnectObjectPushRequest());
+    case Request::TDisconnectHeadsetRequest:
+      return actor->DoRequest(aRequest.get_DisconnectHeadsetRequest());
+    case Request::TDisconnectObjectPushRequest:
+      return actor->DoRequest(aRequest.get_DisconnectObjectPushRequest());
     default:
       MOZ_NOT_REACHED("Unknown type!");
       return false;
   }
 
   MOZ_NOT_REACHED("Should never get here!");
   return false;
 }
@@ -481,8 +489,52 @@ BluetoothRequestParent::DoRequest(const 
     mService->SetAuthorizationInternal(aRequest.path(),
                                        false,
                                        mReplyRunnable.get());
 
   NS_ENSURE_TRUE(result, false);
 
   return true;
 }
+
+bool
+BluetoothRequestParent::DoRequest(const ConnectHeadsetRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TConnectHeadsetRequest);
+
+  return mService->ConnectHeadset(aRequest.address(),
+                                  aRequest.adapterPath(),
+                                  mReplyRunnable.get());
+}
+
+bool
+BluetoothRequestParent::DoRequest(const ConnectObjectPushRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TConnectObjectPushRequest);
+
+  return mService->ConnectObjectPush(aRequest.address(),
+                                     aRequest.adapterPath(),
+                                     mReplyRunnable.get());
+}
+
+bool
+BluetoothRequestParent::DoRequest(const DisconnectHeadsetRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TDisconnectHeadsetRequest);
+
+  mService->DisconnectHeadset(mReplyRunnable.get());
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const DisconnectObjectPushRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TDenyAuthorizationRequest);
+
+  mService->DisconnectObjectPush(mReplyRunnable.get());
+
+  return true;
+}
--- a/dom/bluetooth/ipc/BluetoothParent.h
+++ b/dom/bluetooth/ipc/BluetoothParent.h
@@ -160,13 +160,25 @@ protected:
   bool
   DoRequest(const DenyPairingConfirmationRequest& aRequest);
 
   bool
   DoRequest(const ConfirmAuthorizationRequest& aRequest);
 
   bool
   DoRequest(const DenyAuthorizationRequest& aRequest);
+
+  bool
+  DoRequest(const ConnectHeadsetRequest& aRequest);
+
+  bool
+  DoRequest(const ConnectObjectPushRequest& aRequest);
+
+  bool
+  DoRequest(const DisconnectHeadsetRequest& aRequest);
+
+  bool
+  DoRequest(const DisconnectObjectPushRequest& aRequest);
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_ipc_bluetoothparent_h__
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -197,16 +197,27 @@ BluetoothServiceChildProcess::RemoveDevi
                                               BluetoothReplyRunnable* aRunnable)
 {
   SendRequest(aRunnable,
               UnpairRequest(nsString(aAdapterPath), nsString(aObjectPath)));
   return NS_OK;
 }
 
 nsresult
+BluetoothServiceChildProcess::GetScoSocket(
+                                    const nsAString& aObjectPath,
+                                    bool aAuth,
+                                    bool aEncrypt,
+                                    mozilla::ipc::UnixSocketConsumer* aConsumer)
+{
+  MOZ_NOT_REACHED("This should never be called!");
+  return NS_ERROR_FAILURE;
+}
+
+nsresult
 BluetoothServiceChildProcess::GetSocketViaService(
                                        const nsAString& aObjectPath,
                                        const nsAString& aService,
                                        BluetoothSocketType aType,
                                        bool aAuth,
                                        bool aEncrypt,
                                        mozilla::ipc::UnixSocketConsumer* aConsumer,
                                        BluetoothReplyRunnable* aRunnable)
@@ -271,16 +282,55 @@ BluetoothServiceChildProcess::SetAuthori
 
 nsresult
 BluetoothServiceChildProcess::PrepareAdapterInternal(const nsAString& aPath)
 {
   MOZ_NOT_REACHED("Should never be called from child");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+bool
+BluetoothServiceChildProcess::ConnectHeadset(
+  const nsAString& aDeviceAddress,
+  const nsAString& aAdapterPath,
+  BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable,
+              ConnectHeadsetRequest(nsString(aDeviceAddress), 
+                                    nsString(aAdapterPath)));
+
+  return true;
+}
+
+void
+BluetoothServiceChildProcess::DisconnectHeadset(
+  BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, DisconnectHeadsetRequest());
+}
+
+bool
+BluetoothServiceChildProcess::ConnectObjectPush(
+  const nsAString& aDeviceAddress,
+  const nsAString& aAdapterPath,
+  BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable,
+              ConnectObjectPushRequest(nsString(aDeviceAddress), 
+                                       nsString(aAdapterPath)));
+  return true;
+}
+
+void
+BluetoothServiceChildProcess::DisconnectObjectPush(
+  BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, DisconnectObjectPushRequest());
+}
+
 nsresult
 BluetoothServiceChildProcess::HandleStartup()
 {
   // Don't need to do anything here for startup since our Create function takes
   // care of the actor machinery.
   return NS_OK;
 }
 
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
@@ -82,16 +82,22 @@ public:
                              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
   RemoveDeviceInternal(const nsAString& aAdapterPath,
                        const nsAString& aObjectPath,
                        BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
+  GetScoSocket(const nsAString& aObjectPath,
+               bool aAuth,
+               bool aEncrypt,
+               mozilla::ipc::UnixSocketConsumer* aConsumer) MOZ_OVERRIDE;
+
+  virtual nsresult
   GetSocketViaService(const nsAString& aObjectPath,
                       const nsAString& aService,
                       BluetoothSocketType aType,
                       bool aAuth,
                       bool aEncrypt,
                       mozilla::ipc::UnixSocketConsumer* aConsumer,
                       BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
@@ -111,16 +117,32 @@ public:
                                  BluetoothReplyRunnable* aRunnable)
                                  MOZ_OVERRIDE;
 
   virtual bool
   SetAuthorizationInternal(const nsAString& aDeviceAddress,
                            bool aAllow,
                            BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
+  virtual bool
+  ConnectHeadset(const nsAString& aDeviceAddress,
+                 const nsAString& aAdapterPath,
+                 BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual void
+  DisconnectHeadset(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual bool
+  ConnectObjectPush(const nsAString& aDeviceAddress,
+                    const nsAString& aAdapterPath,
+                    BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual void
+  DisconnectObjectPush(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
 protected:
   BluetoothServiceChildProcess();
   virtual ~BluetoothServiceChildProcess();
 
   void
   NoteDeadActor();
 
   void
--- a/dom/bluetooth/ipc/PBluetooth.ipdl
+++ b/dom/bluetooth/ipc/PBluetooth.ipdl
@@ -92,32 +92,54 @@ struct DenyAuthorizationRequest
   nsString path;
 };
 
 struct DevicePropertiesRequest
 {
   nsString[] addresses;
 };
 
+struct ConnectHeadsetRequest
+{
+  nsString address;
+  nsString adapterPath;
+};
+
+struct ConnectObjectPushRequest
+{
+  nsString address;
+  nsString adapterPath;
+};
+
+struct DisconnectHeadsetRequest
+{};
+
+struct DisconnectObjectPushRequest
+{};
+
 union Request
 {
   DefaultAdapterPathRequest;
   SetPropertyRequest;
   GetPropertyRequest;
   StartDiscoveryRequest;
   StopDiscoveryRequest;
   PairRequest;
   UnpairRequest;
   SetPinCodeRequest;
   SetPasskeyRequest;
   ConfirmPairingConfirmationRequest;
   DenyPairingConfirmationRequest;
   ConfirmAuthorizationRequest;
   DenyAuthorizationRequest;
   DevicePropertiesRequest;
+  ConnectHeadsetRequest;
+  ConnectObjectPushRequest;
+  DisconnectHeadsetRequest;
+  DisconnectObjectPushRequest;
 };
 
 protocol PBluetooth
 {
   manager PContent;
   manages PBluetoothRequest;
 
   /**
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -13,28 +13,34 @@
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 #include "base/basictypes.h"
 #include "BluetoothDBusService.h"
+#include "BluetoothHfpManager.h"
+#include "BluetoothOppManager.h"
+#include "BluetoothReplyRunnable.h"
+#include "BluetoothScoManager.h"
 #include "BluetoothServiceUuid.h"
-#include "BluetoothReplyRunnable.h"
 #include "BluetoothUnixSocketConnector.h"
 
 #include <cstdio>
 #include <dbus/dbus.h>
 
 #include "nsIDOMDOMRequest.h"
+#include "nsIObserverService.h"
+#include "AudioManager.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "nsDebug.h"
 #include "nsDataHashtable.h"
+#include "mozilla/Hal.h"
 #include "mozilla/ipc/UnixSocket.h"
 #include "mozilla/ipc/DBusThread.h"
 #include "mozilla/ipc/DBusUtils.h"
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 /**
@@ -63,16 +69,17 @@ USING_BLUETOOTH_NAMESPACE
 #define B2G_AGENT_CAPABILITIES "DisplayYesNo"
 #define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager"
 #define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
 #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
 #define DBUS_AGENT_IFACE BLUEZ_DBUS_BASE_IFC ".Agent"
 #define BLUEZ_DBUS_BASE_PATH      "/org/bluez"
 #define BLUEZ_DBUS_BASE_IFC       "org.bluez"
 #define BLUEZ_ERROR_IFC           "org.bluez.Error"
+#define BLUETOOTH_SCO_STATUS_CHANGED "bluetooth-sco-status-changed"
 
 typedef struct {
   const char* name;
   int type;
 } Properties;
 
 static Properties sDeviceProperties[] = {
   {"Address", DBUS_TYPE_STRING},
@@ -195,16 +202,44 @@ public:
       NS_WARNING("BluetoothService not available!");
       return NS_ERROR_FAILURE;
     }
     bs->DistributeSignal(mSignal);
     return NS_OK;
   }
 };
 
+class NotifyAudioManagerTask : public nsRunnable {
+public:
+  NotifyAudioManagerTask(nsString aObjectPath) : 
+    mObjectPath(aObjectPath)
+  {
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIAudioManager> am = do_GetService("@mozilla.org/telephony/audiomanager;1");
+    am->SetForceForUse(am->USE_COMMUNICATION, am->FORCE_BT_SCO);
+
+    nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
+    if (obs) {
+      if (NS_FAILED(obs->NotifyObservers(nullptr, BLUETOOTH_SCO_STATUS_CHANGED, mObjectPath.get()))) {
+        NS_WARNING("Failed to notify bluetooth-sco-status-changed observsers!");
+        return NS_ERROR_FAILURE;
+      }
+    }
+    return NS_OK;
+  }
+private:
+  nsString mObjectPath;
+};
+
 class PrepareAdapterTask : public nsRunnable {
 public:
   PrepareAdapterTask(const nsAString& aPath) :
     mPath(aPath)
   {
   }
 
   NS_IMETHOD
@@ -2159,16 +2194,109 @@ BluetoothDBusService::PrepareAdapterInte
   if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Cannot dispatch task!");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
+bool
+BluetoothDBusService::ConnectHeadset(const nsAString& aDeviceAddress,
+                                     const nsAString& aAdapterPath,
+                                     BluetoothReplyRunnable* aRunnable)
+{
+  BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+  return hfp->Connect(GetObjectPathFromAddress(aAdapterPath, aDeviceAddress),
+                      aRunnable);
+}
+
+void
+BluetoothDBusService::DisconnectHeadset(BluetoothReplyRunnable* aRunnable)
+{
+  BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+  hfp->Disconnect();
+
+  // Currently, just fire success because Disconnect() doesn't fail, 
+  // but we still make aRunnable pass into this function for future
+  // once Disconnect will fail.
+  nsString replyError;
+  BluetoothValue v = true;
+  DispatchBluetoothReply(aRunnable, v, replyError);
+}
+
+bool
+BluetoothDBusService::ConnectObjectPush(const nsAString& aDeviceAddress,
+                                        const nsAString& aAdapterPath,
+                                        BluetoothReplyRunnable* aRunnable)
+{
+  BluetoothOppManager* opp = BluetoothOppManager::Get();
+  return opp->Connect(GetObjectPathFromAddress(aAdapterPath, aDeviceAddress),
+                      aRunnable);
+}
+
+void
+BluetoothDBusService::DisconnectObjectPush(BluetoothReplyRunnable* aRunnable)
+{
+  BluetoothOppManager* opp = BluetoothOppManager::Get();
+  opp->Disconnect();
+  
+  // Currently, just fire success because Disconnect() doesn't fail, 
+  // but we still make aRunnable pass into this function for future
+  // once Disconnect will fail.
+  nsString replyError;
+  BluetoothValue v = true;
+  DispatchBluetoothReply(aRunnable, v, replyError);
+}
+class CreateBluetoothScoSocket : public nsRunnable
+{
+public: 
+  CreateBluetoothScoSocket(UnixSocketConsumer* aConsumer,
+                           const nsAString& aObjectPath,
+                           bool aAuth,
+                           bool aEncrypt)
+    : mConsumer(aConsumer),
+      mObjectPath(aObjectPath),
+      mAuth(aAuth),
+      mEncrypt(aEncrypt)
+  {
+  }
+
+  nsresult
+  Run()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    nsString address = GetAddressFromObjectPath(mObjectPath);
+    nsString replyError;
+    BluetoothUnixSocketConnector c(BluetoothSocketType::SCO, -1, mAuth, mEncrypt);
+
+    BluetoothScoManager* sco = BluetoothScoManager::Get();
+    if (!mConsumer->ConnectSocket(c, NS_ConvertUTF16toUTF8(address).get())) {
+      replyError.AssignLiteral("SocketConnectionError");
+      sco->SetConnected(false); 
+      return NS_ERROR_FAILURE;
+    }
+    sco->SetConnected(true);
+
+    nsRefPtr<NotifyAudioManagerTask> task = new NotifyAudioManagerTask(address);
+    if (NS_FAILED(NS_DispatchToMainThread(task))) {
+      NS_WARNING("Failed to dispatch to main thread!");
+      return NS_ERROR_FAILURE;
+    }    
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<UnixSocketConsumer> mConsumer;
+  nsString mObjectPath;
+  bool mAuth;
+  bool mEncrypt;
+};
+
 class CreateBluetoothSocketRunnable : public nsRunnable
 {
 public:
   CreateBluetoothSocketRunnable(BluetoothReplyRunnable* aRunnable,
                                 UnixSocketConsumer* aConsumer,
                                 const nsAString& aObjectPath,
                                 const nsAString& aServiceUUID,
                                 BluetoothSocketType aType,
@@ -2213,16 +2341,40 @@ private:
   nsString mObjectPath;
   nsString mServiceUUID;
   BluetoothSocketType mType;
   bool mAuth;
   bool mEncrypt;
 };
 
 nsresult
+BluetoothDBusService::GetScoSocket(const nsAString& aObjectPath,
+                                   bool aAuth,
+                                   bool aEncrypt,
+                                   mozilla::ipc::UnixSocketConsumer* aConsumer)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+  if (!mConnection || !gThreadConnection) {
+    NS_ERROR("Bluetooth service not started yet!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<nsRunnable> func(new CreateBluetoothScoSocket(aConsumer,
+                                                         aObjectPath,
+                                                         aAuth,
+                                                         aEncrypt));
+  if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
+    NS_WARNING("Cannot dispatch firmware loading task!");
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK; 
+}
+
+nsresult
 BluetoothDBusService::GetSocketViaService(const nsAString& aObjectPath,
                                           const nsAString& aService,
                                           BluetoothSocketType aType,
                                           bool aAuth,
                                           bool aEncrypt,
                                           mozilla::ipc::UnixSocketConsumer* aConsumer,
                                           BluetoothReplyRunnable* aRunnable)
 {
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -63,16 +63,22 @@ public:
                               const nsTArray<uint32_t>& aServices,
                               nsTArray<uint32_t>& aServiceHandlesContainer);
 
   static bool
   RemoveReservedServicesInternal(const nsAString& aAdapterPath,
                                  const nsTArray<uint32_t>& aServiceHandles);
 
   virtual nsresult
+  GetScoSocket(const nsAString& aObjectPath,
+               bool aAuth,
+               bool aEncrypt,
+               mozilla::ipc::UnixSocketConsumer* aConsumer);
+
+  virtual nsresult
   GetSocketViaService(const nsAString& aObjectPath,
                       const nsAString& aService,
                       BluetoothSocketType aType,
                       bool aAuth,
                       bool aEncrypt,
                       mozilla::ipc::UnixSocketConsumer* aConsumer,
                       BluetoothReplyRunnable* aRunnable);
 
@@ -101,16 +107,32 @@ public:
 
   virtual bool
   SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow,
                            BluetoothReplyRunnable* aRunnable);
 
   virtual nsresult
   PrepareAdapterInternal(const nsAString& aPath);
 
+  virtual bool
+  ConnectHeadset(const nsAString& aDeviceAddress,
+                 const nsAString& aAdapterPath,
+                 BluetoothReplyRunnable* aRunnable);
+
+  virtual void
+  DisconnectHeadset(BluetoothReplyRunnable* aRunnable);
+
+  virtual bool
+  ConnectObjectPush(const nsAString& aDeviceAddress,
+                    const nsAString& aAdapterPath,
+                    BluetoothReplyRunnable* aRunnable);
+
+  virtual void
+  DisconnectObjectPush(BluetoothReplyRunnable* aRunnable);
+
 private:
   nsresult SendGetPropertyMessage(const nsAString& aPath,
                                   const char* aInterface,
                                   void (*aCB)(DBusMessage *, void *),
                                   BluetoothReplyRunnable* aRunnable);
   nsresult SendDiscoveryMessage(const nsAString& aAdapterPath,
                                 const char* aMessageName,
                                 BluetoothReplyRunnable* aRunnable);
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl
@@ -2,19 +2,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMRequest;
+interface nsIDOMBlob;
 interface nsIDOMBluetoothDevice;
 
-[scriptable, builtinclass, uuid(df1465c6-00b7-49ab-bd20-1b63721d118f)]
+[scriptable, builtinclass, uuid(ad42ba9f-4c30-4ed5-80c2-8b8520a50e0b)]
 interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
 {
   readonly attribute DOMString address;
   [binaryname(AdapterClass)] readonly attribute unsigned long class;
   readonly attribute bool enabled;
   readonly attribute bool discovering;
 
   [implicit_jscontext]
@@ -36,16 +37,31 @@ interface nsIDOMBluetoothAdapter : nsIDO
   nsIDOMDOMRequest pair(in nsIDOMBluetoothDevice aDevice);
   nsIDOMDOMRequest unpair(in nsIDOMBluetoothDevice aDevice);
   nsIDOMDOMRequest getPairedDevices();
   nsIDOMDOMRequest setPinCode(in DOMString aDeviceAddress, in DOMString aPinCode);
   nsIDOMDOMRequest setPasskey(in DOMString aDeviceAddress, in unsigned long aPasskey);
   nsIDOMDOMRequest setPairingConfirmation(in DOMString aDeviceAddress, in bool aConfirmation);
   nsIDOMDOMRequest setAuthorization(in DOMString aDeviceAddress, in bool aAllow);
 
+  /** 
+   * Connect/Disconnect to a specific service of a target remote device. 
+   * To check the value of service UUIDs, please check "Bluetooth Assigned 
+   * Numbers" / "Service Discovery Protocol" for more information.
+   *  
+   * @param aDeviceAddress Remote device address
+   * @param aProfile 2-octets service UUID
+   */
+  nsIDOMDOMRequest connect(in DOMString aDeviceAddress, in unsigned short aProfile);
+  nsIDOMDOMRequest disconnect(in unsigned short aProfile);
+
+  // One device can only send one file at a time
+  nsIDOMDOMRequest sendFile(in DOMString aDeviceAddress, in nsIDOMBlob aBlob);
+  nsIDOMDOMRequest stopSendingFile(in DOMString aDeviceAddress);
+
   // Fired when discoverying and any device is discovered.
   [implicit_jscontext] attribute jsval ondevicefound;
   // Fired when any device is out of discoverable range.
   [implicit_jscontext] attribute jsval ondevicedisappeared;
   // Fired when any device is created.
   [implicit_jscontext] attribute jsval ondevicecreated;
   // Fired when a property of the adapter is changed
   [implicit_jscontext] attribute jsval onpropertychanged;
--- a/dom/browser-element/BrowserElementScrolling.js
+++ b/dom/browser-element/BrowserElementScrolling.js
@@ -201,52 +201,30 @@ const ContentPanning = {
   get _asyncPanZoomForViewportFrame() {
     return docShell.asyncPanZoomEnabled;
   },
 
   _recvViewportChange: function(data) {
     let metrics = data.json;
     let displayPort = metrics.displayPort;
 
-    let screenWidth = metrics.screenSize.width;
-    let screenHeight = metrics.screenSize.height;
+    let compositionWidth = metrics.compositionBounds.width;
+    let compositionHeight = metrics.compositionBounds.height;
 
     let x = metrics.x;
     let y = metrics.y;
 
     this._zoom = metrics.zoom;
     this._viewport = new Rect(x, y,
-                              screenWidth / metrics.zoom,
-                              screenHeight / metrics.zoom);
+                              compositionWidth / metrics.zoom,
+                              compositionHeight / metrics.zoom);
     this._cssPageRect = new Rect(metrics.cssPageRect.x,
                                  metrics.cssPageRect.y,
                                  metrics.cssPageRect.width,
                                  metrics.cssPageRect.height);
-
-    let cwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-    if (this._screenWidth != screenWidth || this._screenHeight != screenHeight) {
-      cwu.setCSSViewport(screenWidth, screenHeight);
-      this._screenWidth = screenWidth;
-      this._screenHeight = screenHeight;
-    }
-
-    // Set scroll position
-    cwu.setScrollPositionClampingScrollPortSize(
-      screenWidth / metrics.zoom, screenHeight / metrics.zoom);
-    content.scrollTo(x, y);
-    cwu.setResolution(displayPort.resolution, displayPort.resolution);
-
-    let element = null;
-    if (content.document && (element = content.document.documentElement)) {
-      cwu.setDisplayPortForElement(displayPort.left,
-                                   displayPort.top,
-                                   displayPort.width,
-                                   displayPort.height,
-                                   element);
-    }
   },
 
   _recvDoubleTap: function(data) {
     let data = data.json;
 
     // We haven't received a metrics update yet; don't do anything.
     if (this._viewport == null) {
       return;
@@ -267,17 +245,17 @@ const ContentPanning = {
     if (!element) {
       this._zoomOut();
     } else {
       const margin = 15;
       let rect = ElementTouchHelper.getBoundingContentRect(element);
 
       let cssPageRect = this._cssPageRect;
       let viewport = this._viewport;
-      let bRect = new Rect(Math.max(cssPageRect.left, rect.x - margin),
+      let bRect = new Rect(Math.max(cssPageRect.x, rect.x - margin),
                            rect.y,
                            rect.w + 2 * margin,
                            rect.h);
       // constrict the rect to the screen's right edge
       bRect.width = Math.min(bRect.width, cssPageRect.right - bRect.x);
 
       // if the rect is already taking up most of the visible area and is stretching the
       // width of the page, then we want to zoom out instead.
new file mode 100644
--- /dev/null
+++ b/dom/camera/AudioParameter.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2006-2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioParameter"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <media/AudioParameter.h>
+
+namespace android {
+
+const char *AudioParameter::keyRouting = "routing";
+const char *AudioParameter::keySamplingRate = "sampling_rate";
+const char *AudioParameter::keyFormat = "format";
+const char *AudioParameter::keyChannels = "channels";
+const char *AudioParameter::keyFrameCount = "frame_count";
+const char *AudioParameter::keyInputSource = "input_source";
+
+AudioParameter::AudioParameter(const String8& keyValuePairs)
+{
+    char *str = new char[keyValuePairs.length()+1];
+    mKeyValuePairs = keyValuePairs;
+
+    strcpy(str, keyValuePairs.string());
+    char *pair = strtok(str, ";");
+    while (pair != NULL) {
+        if (strlen(pair) != 0) {
+            size_t eqIdx = strcspn(pair, "=");
+            String8 key = String8(pair, eqIdx);
+            String8 value;
+            if (eqIdx == strlen(pair)) {
+                value = String8("");
+            } else {
+                value = String8(pair + eqIdx + 1);
+            }
+            if (mParameters.indexOfKey(key) < 0) {
+                mParameters.add(key, value);
+            } else {
+                mParameters.replaceValueFor(key, value);
+            }
+        } else {
+            LOGV("AudioParameter() cstor empty key value pair");
+        }
+        pair = strtok(NULL, ";");
+    }
+
+    delete[] str;
+}
+
+AudioParameter::~AudioParameter()
+{
+    mParameters.clear();
+}
+
+String8 AudioParameter::toString()
+{
+    String8 str = String8("");
+
+    size_t size = mParameters.size();
+    for (size_t i = 0; i < size; i++) {
+        str += mParameters.keyAt(i);
+        str += "=";
+        str += mParameters.valueAt(i);
+        if (i < (size - 1)) str += ";";
+    }
+    return str;
+}
+
+status_t AudioParameter::add(const String8& key, const String8& value)
+{
+    if (mParameters.indexOfKey(key) < 0) {
+        mParameters.add(key, value);
+        return NO_ERROR;
+    } else {
+        mParameters.replaceValueFor(key, value);
+        return ALREADY_EXISTS;
+    }
+}
+
+status_t AudioParameter::addInt(const String8& key, const int value)
+{
+    char str[12];
+    if (snprintf(str, 12, "%d", value) > 0) {
+        String8 str8 = String8(str);
+        return add(key, str8);
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::addFloat(const String8& key, const float value)
+{
+    char str[23];
+    if (snprintf(str, 23, "%.10f", value) > 0) {
+        String8 str8 = String8(str);
+        return add(key, str8);
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::remove(const String8& key)
+{
+    if (mParameters.indexOfKey(key) >= 0) {
+        mParameters.removeItem(key);
+        return NO_ERROR;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::get(const String8& key, String8& value)
+{
+    if (mParameters.indexOfKey(key) >= 0) {
+        value = mParameters.valueFor(key);
+        return NO_ERROR;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::getInt(const String8& key, int& value)
+{
+    String8 str8;
+    status_t result = get(key, str8);
+    value = 0;
+    if (result == NO_ERROR) {
+        int val;
+        if (sscanf(str8.string(), "%d", &val) == 1) {
+            value = val;
+        } else {
+            result = INVALID_OPERATION;
+        }
+    }
+    return result;
+}
+
+status_t AudioParameter::getFloat(const String8& key, float& value)
+{
+    String8 str8;
+    status_t result = get(key, str8);
+    value = 0;
+    if (result == NO_ERROR) {
+        float val;
+        if (sscanf(str8.string(), "%f", &val) == 1) {
+            value = val;
+        } else {
+            result = INVALID_OPERATION;
+        }
+    }
+    return result;
+}
+
+status_t AudioParameter::getAt(size_t index, String8& key, String8& value)
+{
+    if (mParameters.size() > index) {
+        key = mParameters.keyAt(index);
+        value = mParameters.valueAt(index);
+        return NO_ERROR;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+};  // namespace android
--- a/dom/camera/CameraControlImpl.cpp
+++ b/dom/camera/CameraControlImpl.cpp
@@ -191,19 +191,19 @@ CameraControlImpl::AutoFocus(nsICameraAu
 nsresult
 CameraControlImpl::TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
 {
   nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, aSize, aRotation, aFileFormat, aPosition, onSuccess, onError);
   return mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL);
 }
 
 nsresult
-CameraControlImpl::StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
+CameraControlImpl::StartRecording(nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
 {
-  nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, aSize, onSuccess, onError);
+  nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, aStorageArea, aFilename, onSuccess, onError);
   return mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
 }
 
 nsresult
 CameraControlImpl::StopRecording()
 {
   nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this);
   return mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
@@ -218,16 +218,23 @@ CameraControlImpl::StartPreview(DOMCamer
 
 void
 CameraControlImpl::StopPreview()
 {
   nsCOMPtr<nsIRunnable> stopPreviewTask = new StopPreviewTask(this);
   mCameraThread->Dispatch(stopPreviewTask, NS_DISPATCH_NORMAL);
 }
 
+nsresult
+CameraControlImpl::GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+  nsCOMPtr<nsIRunnable> getPreviewStreamVideoModeTask = new GetPreviewStreamVideoModeTask(this, *aOptions, onSuccess, onError);
+  return mCameraThread->Dispatch(getPreviewStreamVideoModeTask, NS_DISPATCH_NORMAL);
+}
+
 bool
 CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
 {
   if (!mDOMPreview) {
     return false;
   }
 
   return mDOMPreview->ReceiveFrame(aBuffer, aFormat, aBuilder);
--- a/dom/camera/CameraControlImpl.h
+++ b/dom/camera/CameraControlImpl.h
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DOM_CAMERA_CAMERACONTROLIMPL_H
 #define DOM_CAMERA_CAMERACONTROLIMPL_H
 
 #include "nsCOMPtr.h"
 #include "nsDOMFile.h"
 #include "DictionaryHelpers.h"
+#include "nsIDOMDeviceStorage.h"
 #include "nsIDOMCameraManager.h"
 #include "ICameraControl.h"
 #include "CameraCommon.h"
 
 namespace mozilla {
 
 using namespace dom;
 
@@ -20,30 +21,32 @@ class GetPreviewStreamTask;
 class StartPreviewTask;
 class StopPreviewTask;
 class AutoFocusTask;
 class TakePictureTask;
 class StartRecordingTask;
 class StopRecordingTask;
 class SetParameterTask;
 class GetParameterTask;
+class GetPreviewStreamVideoModeTask;
 
 class DOMCameraPreview;
 
 class CameraControlImpl : public ICameraControl
 {
   friend class GetPreviewStreamTask;
   friend class StartPreviewTask;
   friend class StopPreviewTask;
   friend class AutoFocusTask;
   friend class TakePictureTask;
   friend class StartRecordingTask;
   friend class StopRecordingTask;
   friend class SetParameterTask;
   friend class GetParameterTask;
+  friend class GetPreviewStreamVideoModeTask;
 
 public:
   CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread)
     : mCameraId(aCameraId)
     , mCameraThread(aCameraThread)
     , mFileFormat()
     , mMaxMeteringAreas(0)
     , mMaxFocusAreas(0)
@@ -59,18 +62,19 @@ public:
     DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   }
 
   nsresult GetPreviewStream(CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError);
   nsresult StartPreview(DOMCameraPreview* aDOMPreview);
   void StopPreview();
   nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError);
   nsresult TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError);
-  nsresult StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError);
+  nsresult StartRecording(nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError);
   nsresult StopRecording();
+  nsresult GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError);
 
   nsresult Set(uint32_t aKey, const nsAString& aValue);
   nsresult Get(uint32_t aKey, nsAString& aValue);
   nsresult Set(uint32_t aKey, double aValue);
   nsresult Get(uint32_t aKey, double* aValue);
   nsresult Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit);
   nsresult Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue);
 
@@ -106,16 +110,17 @@ protected:
   virtual nsresult StartPreviewImpl(StartPreviewTask* aStartPreview) = 0;
   virtual nsresult StopPreviewImpl(StopPreviewTask* aStopPreview) = 0;
   virtual nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus) = 0;
   virtual nsresult TakePictureImpl(TakePictureTask* aTakePicture) = 0;
   virtual nsresult StartRecordingImpl(StartRecordingTask* aStartRecording) = 0;
   virtual nsresult StopRecordingImpl(StopRecordingTask* aStopRecording) = 0;
   virtual nsresult PushParametersImpl() = 0;
   virtual nsresult PullParametersImpl() = 0;
+  virtual nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode) = 0;
 
   uint32_t            mCameraId;
   nsCOMPtr<nsIThread> mCameraThread;
   nsString            mFileFormat;
   uint32_t            mMaxMeteringAreas;
   uint32_t            mMaxFocusAreas;
 
   /**
@@ -342,71 +347,74 @@ public:
   nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
 };
 
 // Return the captured video to JS.  Runs on the main thread.
 class StartRecordingResult : public nsRunnable
 {
 public:
-  StartRecordingResult(nsIDOMMediaStream* aStream, nsICameraStartRecordingCallback* onSuccess)
-    : mStream(aStream)
-    , mOnSuccessCb(onSuccess)
+  StartRecordingResult(nsICameraStartRecordingCallback* onSuccess)
+    : mOnSuccessCb(onSuccess)
   { }
 
   virtual ~StartRecordingResult() { }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (mOnSuccessCb) {
-      mOnSuccessCb->HandleEvent(mStream);
+      mOnSuccessCb->HandleEvent();
     }
     return NS_OK;
   }
 
 protected:
-  nsCOMPtr<nsIDOMMediaStream> mStream;
   nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
 };
 
 // Start video recording.
 class StartRecordingTask : public nsRunnable
 {
 public:
-  StartRecordingTask(CameraControlImpl* aCameraControl, CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
-    : mSize(aSize)
-    , mCameraControl(aCameraControl)
+  StartRecordingTask(CameraControlImpl* aCameraControl, nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
+    : mCameraControl(aCameraControl)
+    , mStorageArea(aStorageArea)
+    , mFilename(aFilename)
     , mOnSuccessCb(onSuccess)
     , mOnErrorCb(onError)
   {
     DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   }
 
   virtual ~StartRecordingTask()
   {
     DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   }
 
   NS_IMETHOD Run()
   {
     DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
     nsresult rv = mCameraControl->StartRecordingImpl(this);
-    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d : result %d\n", __func__, __LINE__, rv);
 
-    if (NS_FAILED(rv) && mOnErrorCb) {
+    if (NS_SUCCEEDED(rv)) {
+      if (mOnSuccessCb) {
+        rv = NS_DispatchToMainThread(new StartRecordingResult(mOnSuccessCb));
+      }
+    } else if (mOnErrorCb) {
       rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
-      NS_ENSURE_SUCCESS(rv, rv);
     }
     return rv;
   }
 
-  CameraSize mSize;
   nsRefPtr<CameraControlImpl> mCameraControl;
+  nsCOMPtr<nsIDOMDeviceStorage> mStorageArea;
+  nsString mFilename;
   nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
 };
 
 // Stop video recording.
 class StopRecordingTask : public nsRunnable
 {
 public:
@@ -486,11 +494,72 @@ public:
     DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
     return NS_OK;
   }
 
   nsRefPtr<CameraControlImpl> mCameraControl;
 };
 
+// Return the resulting preview stream to JS.  Runs on the main thread.
+class GetPreviewStreamVideoModeResult : public nsRunnable
+{
+public:
+  GetPreviewStreamVideoModeResult(nsIDOMMediaStream* aStream, nsICameraPreviewStreamCallback* onSuccess)
+     : mStream(aStream)
+     , mOnSuccessCb(onSuccess)
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~GetPreviewStreamVideoModeResult()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (mOnSuccessCb) {
+      mOnSuccessCb->HandleEvent(mStream);
+    }
+    return NS_OK;
+  }
+
+protected:
+  nsCOMPtr<nsIDOMMediaStream> mStream;
+  nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
+};
+
+// Get the video mode preview stream.
+class GetPreviewStreamVideoModeTask : public nsRunnable
+{
+public:
+  GetPreviewStreamVideoModeTask(CameraControlImpl* aCameraControl, CameraRecordingOptions aOptions,  nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
+    : mCameraControl(aCameraControl)
+    , mOptions(aOptions)
+    , mOnSuccessCb(onSuccess)
+    , mOnErrorCb(onError)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    DOM_CAMERA_LOGI("%s:%d -- BEFORE IMPL\n", __func__, __LINE__);
+    nsresult rv = mCameraControl->GetPreviewStreamVideoModeImpl(this);
+    DOM_CAMERA_LOGI("%s:%d -- AFTER IMPL : rv = %d\n", __func__, __LINE__, rv);
+
+    if (NS_FAILED(rv) && mOnErrorCb) {
+      rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+    return NS_OK;
+  }
+
+  nsRefPtr<CameraControlImpl> mCameraControl;
+  CameraRecordingOptions mOptions;
+  nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
+  nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
+};
+
 } // namespace mozilla
 
 #endif // DOM_CAMERA_CAMERACONTROLIMPL_H
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -4,16 +4,17 @@
 
 #include "base/basictypes.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "jsapi.h"
 #include "nsThread.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
+#include "nsIDOMDeviceStorage.h"
 #include "DOMCameraManager.h"
 #include "DOMCameraCapabilities.h"
 #include "DOMCameraControl.h"
 #include "CameraCommon.h"
 
 using namespace mozilla;
 using namespace dom;
 
@@ -213,37 +214,33 @@ nsDOMCameraControl::GetOnShutter(nsICame
 }
 NS_IMETHODIMP
 nsDOMCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
 {
   // TODO: see bug 779138.
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-/* void startRecording (in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
+/* [implicit_jscontext] void startRecording (in nsIDOMDeviceStorage storageArea, in DOMString filename, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
 NS_IMETHODIMP
-nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
+nsDOMCameraControl::StartRecording(nsIDOMDeviceStorage* storageArea, const nsAString& filename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
 {
   NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
 
-  CameraSize size;
-  nsresult rv = size.Init(cx, &aOptions);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (!obs) {
     NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
     return NS_ERROR_FAILURE;
   }
 
   obs->NotifyObservers(nullptr,
                        "recording-device-events",
                        NS_LITERAL_STRING("starting").get());
 
-  return mCameraControl->StartRecording(size, onSuccess, onError);
+  return mCameraControl->StartRecording(storageArea, filename, onSuccess, onError);
 }
 
 /* void stopRecording (); */
 NS_IMETHODIMP
 nsDOMCameraControl::StopRecording()
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (!obs) {
@@ -311,16 +308,29 @@ nsDOMCameraControl::TakePicture(const JS
   pos.altitude = NAN;
   pos.timestamp = NAN;
   rv = pos.Init(cx, &options.position);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return mCameraControl->TakePicture(size, options.rotation, options.fileFormat, pos, onSuccess, onError);
 }
 
+/* [implicit_jscontext] void GetPreviewStreamVideoMode (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
+NS_IMETHODIMP
+nsDOMCameraControl::GetPreviewStreamVideoMode(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
+{
+  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
+
+  CameraRecordingOptions options;
+  nsresult rv = options.Init(cx, &aOptions);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return mCameraControl->GetPreviewStreamVideoMode(&options, onSuccess, onError);
+}
+
 class GetCameraResult : public nsRunnable
 {
 public:
   GetCameraResult(nsDOMCameraControl* aDOMCameraControl, nsresult aResult, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
     : mDOMCameraControl(aDOMCameraControl)
     , mResult(aResult)
     , mOnSuccessCb(onSuccess)
     , mOnErrorCb(onError)
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -10,24 +10,30 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <libgen.h>
 #include "base/basictypes.h"
 #include "libcameraservice/CameraHardwareInterface.h"
 #include "camera/CameraParameters.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "nsMemory.h"
 #include "jsapi.h"
 #include "nsThread.h"
+#include <media/MediaProfiles.h>
+#include "nsDirectoryServiceDefs.h" // for NS_GetSpecialDirectory
 #include "nsPrintfCString.h"
 #include "DOMCameraManager.h"
 #include "GonkCameraHwMgr.h"
 #include "DOMCameraCapabilities.h"
 #include "DOMCameraControl.h"
 #include "GonkCameraControl.h"
 #include "CameraCommon.h"
 
@@ -542,30 +548,38 @@ nsGonkCameraControl::StartPreviewImpl(St
 
   if (aStartPreview->mDOMPreview) {
     mDOMPreview->Started();
   }
   return NS_OK;
 }
 
 nsresult
-nsGonkCameraControl::StopPreviewImpl(StopPreviewTask* aStopPreview)
+nsGonkCameraControl::StopPreviewInternal(bool aForced)
 {
   DOM_CAMERA_LOGI("%s: stopping preview\n", __func__);
 
   // StopPreview() is a synchronous call--it doesn't return
   // until the camera preview thread exits.
-  GonkCameraHardware::StopPreview(mHwHandle);
-  mDOMPreview->Stopped();
-  mDOMPreview = nullptr;
+  if (mDOMPreview) {
+    GonkCameraHardware::StopPreview(mHwHandle);
+    mDOMPreview->Stopped(aForced);
+    mDOMPreview = nullptr;
+  }
 
   return NS_OK;
 }
 
 nsresult
+nsGonkCameraControl::StopPreviewImpl(StopPreviewTask* aStopPreview)
+{
+  return StopPreviewInternal();
+}
+
+nsresult
 nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
 {
   nsCOMPtr<nsICameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb;
   if (cb) {
     /**
      * We already have a callback, so someone has already
      * called autoFocus() -- cancel it.
      */
@@ -686,23 +700,81 @@ nsGonkCameraControl::PullParametersImpl(
   RwAutoLockWrite lock(mRwLock);
   GonkCameraHardware::PullParameters(mHwHandle, mParams);
   return NS_OK;
 }
 
 nsresult
 nsGonkCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  mStartRecordingOnSuccessCb = aStartRecording->mOnSuccessCb;
+  mStartRecordingOnErrorCb = aStartRecording->mOnErrorCb;
+
+  /**
+   * We need to pull in the base path from aStartRecording->mStorageArea
+   * once that feature lands.  See bug 795201.
+   *
+   * For now, we just assume /sdcard/Movies.
+   *
+   * Also, the camera app needs to provide the file extension '.3gp' for now.
+   * See bug 795202.
+   */
+#if 1
+  nsCOMPtr<nsIFile> filename;
+  aStartRecording->mStorageArea->GetRootDirectory(getter_AddRefs(filename));
+  filename->Append(aStartRecording->mFilename);
+
+  nsAutoCString pathname;
+  filename->GetNativePath(pathname);
+#else
+  nsAutoCString pathname(NS_LITERAL_CSTRING("/sdcard/Movies/"));
+  nsAutoCString filename(NS_ConvertUTF16toUTF8(aStartRecording->mFilename));
+
+  // Make sure that the file name doesn't contain any directory components.
+  if (strcmp(filename.get(), basename(filename.get())) != 0) {
+    DOM_CAMERA_LOGE("Video filename '%s' is not valid\n", filename.get());
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  pathname.Append(filename);
+#endif
+  DOM_CAMERA_LOGI("Video pathname is '%s'\n", pathname.get());
+  int fd = open(pathname.get(), O_RDWR | O_CREAT, 0644);
+  if (fd < 0) {
+    DOM_CAMERA_LOGE("Couldn't create file '%s' with error (%d) %s\n", pathname.get(), errno, strerror(errno));
+    return NS_ERROR_FAILURE;
+  }
+
+  if (SetupRecording(fd) != NS_OK) {
+    DOM_CAMERA_LOGE("SetupRecording() failed\n");
+    close(fd);
+    return NS_ERROR_FAILURE;
+  }
+  if (mRecorder->start() != OK) {
+    DOM_CAMERA_LOGE("mRecorder->start() failed\n");
+    close(fd);
+    return NS_ERROR_FAILURE;
+  }
+
+  // dispatch the callback
+  nsCOMPtr<nsIRunnable> startRecordingResult = new StartRecordingResult(mStartRecordingOnSuccessCb);
+  nsresult rv = NS_DispatchToMainThread(startRecordingResult);
+  if (NS_FAILED(rv)) {
+    DOM_CAMERA_LOGE("Failed to dispatch start recording result to main thread (%d)!", rv);
+  }
+  return NS_OK;
 }
 
 nsresult
 nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  mRecorder->stop();
+  delete mRecorder;
+  mRecorder = nullptr;
+  return NS_OK;
 }
 
 void
 nsGonkCameraControl::AutoFocusComplete(bool aSuccess)
 {
   /**
    * Auto focusing can change some of the camera's parameters, so
    * we need to pull a new set before sending the result to the
@@ -804,16 +876,162 @@ nsGonkCameraControl::SetPreviewSize(uint
   }
 
   mWidth = bestWidth;
   mHeight = bestHeight;
   mParams.setPreviewSize(mWidth, mHeight);
   PushParameters();
 }
 
+nsresult
+nsGonkCameraControl::SetupVideoMode()
+{
+  // read preferences for camcorder
+  mMediaProfiles = MediaProfiles::getInstance();
+
+  /**
+   * Right now default to profile 3, which is 352x288 on Otoro.  In the
+   * future, allow the application to select a recording quality and
+   * configuration.
+   *
+   * See bug 795379.
+   */
+  int quality = 3;  // cif:352x288
+  camcorder_quality q = static_cast<camcorder_quality>(quality);
+  mDuration         = mMediaProfiles->getCamcorderProfileParamByName("duration",    (int)mCameraId, q);
+  mVideoFileFormat  = mMediaProfiles->getCamcorderProfileParamByName("file.format", (int)mCameraId, q);
+  mVideoCodec       = mMediaProfiles->getCamcorderProfileParamByName("vid.codec",   (int)mCameraId, q);
+  mVideoBitRate     = mMediaProfiles->getCamcorderProfileParamByName("vid.bps",     (int)mCameraId, q);
+  mVideoFrameRate   = mMediaProfiles->getCamcorderProfileParamByName("vid.fps",     (int)mCameraId, q);
+  mVideoFrameWidth  = mMediaProfiles->getCamcorderProfileParamByName("vid.width",   (int)mCameraId, q);
+  mVideoFrameHeight = mMediaProfiles->getCamcorderProfileParamByName("vid.height",  (int)mCameraId, q);
+  mAudioCodec       = mMediaProfiles->getCamcorderProfileParamByName("aud.codec",   (int)mCameraId, q);
+  mAudioBitRate     = mMediaProfiles->getCamcorderProfileParamByName("aud.bps",     (int)mCameraId, q);
+  mAudioSampleRate  = mMediaProfiles->getCamcorderProfileParamByName("aud.hz",      (int)mCameraId, q);
+  mAudioChannels    = mMediaProfiles->getCamcorderProfileParamByName("aud.ch",      (int)mCameraId, q);
+
+  if (mVideoFrameRate == -1) {
+    DOM_CAMERA_LOGE("Failed to get a valid frame rate!\n");
+    DOM_CAMERA_LOGE("Also got width=%d, height=%d\n", mVideoFrameWidth, mVideoFrameHeight);
+    return NS_ERROR_FAILURE;
+  }
+
+  PullParametersImpl();
+
+  // Configure camera video recording parameters.
+  const size_t SIZE = 256;
+  char buffer[SIZE];
+
+  /**
+   * Ignore the width and height settings from app, just use the one in profile.
+   * Eventually, will try to choose a profile which respects the settings from app.
+   * See bug 795330.
+   */
+  mParams.setPreviewSize(mVideoFrameWidth, mVideoFrameHeight);
+  mParams.setPreviewFrameRate(mVideoFrameRate);
+  snprintf(buffer, SIZE, "%dx%d", mVideoFrameWidth, mVideoFrameHeight);
+
+  /**
+   * "record-size" is probably deprecated in later ICS;
+   * might need to set "video-size" instead of "record-size".
+   * See bug 795332.
+   */
+  mParams.set("record-size", buffer);
+
+  /**
+   * If we want to enable picture-taking _while_ recording video, this sets the
+   * size of the captured picture.  For now, just set it to the same dimensions
+   * as the video we're recording; ideally, we should probably make sure it
+   * matches one of the supported picture sizes.
+   */
+  mParams.setPictureSize(mVideoFrameWidth, mVideoFrameHeight);
+
+  PushParametersImpl();
+  return NS_OK;
+}
+
+#ifndef CHECK_SETARG
+#define CHECK_SETARG(x)                 \
+  do {                                  \
+    if (x) {                            \
+      DOM_CAMERA_LOGE(#x " failed\n");  \
+      return NS_ERROR_INVALID_ARG;      \
+    }                                   \
+  } while(0)
+#endif
+
+nsresult
+nsGonkCameraControl::SetupRecording(int aFd)
+{
+  // choosing a size big enough to hold the params
+  const size_t SIZE = 256;
+  char buffer[SIZE];
+
+  mRecorder = new GonkRecorder();
+  CHECK_SETARG(mRecorder->init());
+
+  // set all the params
+  CHECK_SETARG(mRecorder->setCameraHandle((int32_t)mHwHandle));
+  CHECK_SETARG(mRecorder->setAudioSource(AUDIO_SOURCE_CAMCORDER));
+  CHECK_SETARG(mRecorder->setVideoSource(VIDEO_SOURCE_CAMERA));
+  CHECK_SETARG(mRecorder->setOutputFormat((output_format)mVideoFileFormat));
+  CHECK_SETARG(mRecorder->setVideoFrameRate(mVideoFrameRate));
+  CHECK_SETARG(mRecorder->setVideoSize(mVideoFrameWidth, mVideoFrameHeight));
+  snprintf(buffer, SIZE, "video-param-encoding-bitrate=%d", mVideoBitRate);
+  CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
+  CHECK_SETARG(mRecorder->setVideoEncoder((video_encoder)mVideoCodec));
+  snprintf(buffer, SIZE, "audio-param-encoding-bitrate=%d", mAudioBitRate);
+  CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
+  snprintf(buffer, SIZE, "audio-param-number-of-channels=%d", mAudioChannels);
+  CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
+  snprintf(buffer, SIZE, "audio-param-sampling-rate=%d", mAudioSampleRate);
+  CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
+  CHECK_SETARG(mRecorder->setAudioEncoder((audio_encoder)mAudioCodec));
+  // TODO: For now there is no limit on recording duration (See bug 795090)
+  CHECK_SETARG(mRecorder->setParameters(String8("max-duration=-1")));
+  // TODO: For now there is no limit on file size (See bug 795090)
+  CHECK_SETARG(mRecorder->setParameters(String8("max-filesize=-1")));
+  snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d", mVideoRotation);
+  CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
+
+  // recording API needs file descriptor of output file
+  CHECK_SETARG(mRecorder->setOutputFile(aFd, 0, 0));
+  CHECK_SETARG(mRecorder->prepare());
+  return NS_OK;
+}
+
+nsresult
+nsGonkCameraControl::GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode)
+{
+  nsCOMPtr<GetPreviewStreamResult> getPreviewStreamResult = nullptr;
+
+  // stop any currently running preview
+  StopPreviewInternal(true /* forced */);
+
+  // copy the recording preview options
+  mVideoRotation = aGetPreviewStreamVideoMode->mOptions.rotation;
+  mVideoWidth = aGetPreviewStreamVideoMode->mOptions.width;
+  mVideoHeight = aGetPreviewStreamVideoMode->mOptions.height;
+  DOM_CAMERA_LOGI("recording preview format: %d x %d (w x h) (rotated %d degrees)\n", mVideoWidth, mVideoHeight, mVideoRotation);
+
+  // setup the video mode
+  nsresult rv = SetupVideoMode();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // create and return new preview stream object
+  getPreviewStreamResult = new GetPreviewStreamResult(this, mVideoWidth, mVideoHeight, mVideoFrameRate, aGetPreviewStreamVideoMode->mOnSuccessCb);
+  rv = NS_DispatchToMainThread(getPreviewStreamResult);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to dispatch GetPreviewStreamVideoMode() onSuccess callback to main thread!");
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 // Gonk callback handlers.
 namespace mozilla {
 
 void
 ReceiveImage(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength)
 {
   gc->TakePictureComplete(aData, aLength);
 }
--- a/dom/camera/GonkCameraControl.h
+++ b/dom/camera/GonkCameraControl.h
@@ -19,16 +19,17 @@
 
 #include "base/basictypes.h"
 #include "prtypes.h"
 #include "prrwlock.h"
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraControl.h"
 #include "CameraControlImpl.h"
 #include "CameraCommon.h"
+#include "GonkRecorder.h"
 
 namespace mozilla {
 
 namespace layers {
 class GraphicBufferLocked;
 }
 
 class nsGonkCameraControl : public CameraControlImpl
@@ -42,31 +43,36 @@ public:
   double GetParameterDouble(uint32_t aKey);
   void GetParameter(uint32_t aKey, nsTArray<dom::CameraRegion>& aRegions);
   void SetParameter(const char* aKey, const char* aValue);
   void SetParameter(uint32_t aKey, const char* aValue);
   void SetParameter(uint32_t aKey, double aValue);
   void SetParameter(uint32_t aKey, const nsTArray<dom::CameraRegion>& aRegions);
   nsresult PushParameters();
 
+  nsresult SetupRecording(int aFd);
+  nsresult SetupVideoMode();
+
   void AutoFocusComplete(bool aSuccess);
   void TakePictureComplete(uint8_t* aData, uint32_t aLength);
 
 protected:
   ~nsGonkCameraControl();
 
   nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
   nsresult StartPreviewImpl(StartPreviewTask* aStartPreview);
   nsresult StopPreviewImpl(StopPreviewTask* aStopPreview);
+  nsresult StopPreviewInternal(bool aForced = false);
   nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
   nsresult TakePictureImpl(TakePictureTask* aTakePicture);
   nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
   nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
   nsresult PushParametersImpl();
   nsresult PullParametersImpl();
+  nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode);
 
   void SetPreviewSize(uint32_t aWidth, uint32_t aHeight);
 
   uint32_t                  mHwHandle;
   double                    mExposureCompensationMin;
   double                    mExposureCompensationStep;
   bool                      mDeferConfigUpdate;
   PRRWLock*                 mRwLock;
@@ -79,16 +85,37 @@ protected:
     PREVIEW_FORMAT_YUV420P,
     PREVIEW_FORMAT_YUV420SP
   };
   uint32_t                  mFormat;
 
   uint32_t                  mFps;
   uint32_t                  mDiscardedFrameCount;
 
+  android::MediaProfiles*   mMediaProfiles;
+  android::GonkRecorder*    mRecorder;
+
+  PRUint32                  mVideoRotation;
+  PRUint32                  mVideoWidth;
+  PRUint32                  mVideoHeight;
+  nsString                  mVideoFile;
+
+  // camcorder profile settings for the desired quality level
+  int mDuration;        // max recording duration (ignored)
+  int mVideoFileFormat; // output file format
+  int mVideoCodec;      // video encoder
+  int mVideoBitRate;    // video bit rate
+  int mVideoFrameRate;  // video frame rate
+  int mVideoFrameWidth; // video frame width
+  int mVideoFrameHeight;// video frame height
+  int mAudioCodec;      // audio encoder
+  int mAudioBitRate;    // audio bit rate
+  int mAudioSampleRate; // audio sample rate
+  int mAudioChannels;   // number of audio channels
+
 private:
   nsGonkCameraControl(const nsGonkCameraControl&) MOZ_DELETE;
   nsGonkCameraControl& operator=(const nsGonkCameraControl&) MOZ_DELETE;
 };
 
 // camera driver callbacks
 void ReceiveImage(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
 void AutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
--- a/dom/camera/GonkCameraHwMgr.cpp
+++ b/dom/camera/GonkCameraHwMgr.cpp
@@ -139,16 +139,44 @@ GonkCameraHardware::NotifyCallback(int32
 
     default:
       DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType);
       break;
   }
 }
 
 void
+GonkCameraHardware::DataCallbackTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory> &aDataPtr, void* aUser)
+{
+  DOM_CAMERA_LOGI("%s",__func__);
+  GonkCameraHardware* hw = GetHardware((uint32_t)aUser);
+  if (!hw) {
+    DOM_CAMERA_LOGE("%s:aUser = %d resolved to no camera hw\n", __func__, (uint32_t)aUser);
+    return;
+  }
+  if (hw->mClosing) {
+    return;
+  }
+
+  sp<GonkCameraListener> listener;
+  {
+    //TODO
+    //Mutex::Autolock _l(hw->mLock);
+    listener = hw->mListener;
+  }
+  if (listener.get()) {
+    DOM_CAMERA_LOGI("Listener registered, posting recording frame!");
+    listener->postDataTimestamp(aTimestamp, aMsgType, aDataPtr);
+  } else {
+    DOM_CAMERA_LOGW("No listener was set. Drop a recording frame.");
+    hw->mHardware->releaseRecordingFrame(aDataPtr);
+  }
+}
+
+void
 GonkCameraHardware::Init()
 {
   DOM_CAMERA_LOGT("%s: this=%p\n", __func__, (void* )this);
 
   if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t**)&mModule) < 0) {
     return;
   }
   char cameraDeviceName[4];
@@ -157,17 +185,17 @@ GonkCameraHardware::Init()
   if (mHardware->initialize(&mModule->common) != OK) {
     mHardware.clear();
     return;
   }
 
   if (sHwHandle == 0) {
     sHwHandle = 1;  // don't use 0
   }
-  mHardware->setCallbacks(GonkCameraHardware::NotifyCallback, GonkCameraHardware::DataCallback, NULL, (void*)sHwHandle);
+  mHardware->setCallbacks(GonkCameraHardware::NotifyCallback, GonkCameraHardware::DataCallback, GonkCameraHardware::DataCallbackTimestamp, (void*)sHwHandle);
   mInitialized = true;
 }
 
 GonkCameraHardware::~GonkCameraHardware()
 {
   DOM_CAMERA_LOGT( "%s:%d : this=%p\n", __func__, __LINE__, (void*)this );
   sHw = nullptr;
 }
@@ -309,8 +337,86 @@ GonkCameraHardware::StartPreview(uint32_
 void
 GonkCameraHardware::StopPreview(uint32_t aHwHandle)
 {
   GonkCameraHardware* hw = GetHardware(aHwHandle);
   if (hw) {
     hw->mHardware->stopPreview();
   }
 }
+
+int
+GonkCameraHardware::StartRecording(uint32_t aHwHandle)
+{
+  DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
+  int rv = OK;
+  GonkCameraHardware* hw = GetHardware(aHwHandle);
+  if (!hw) {
+    return DEAD_OBJECT;
+  }
+
+  if (hw->mHardware->recordingEnabled()) {
+    return OK;
+  }
+
+  if (!hw->mHardware->previewEnabled()) {
+    DOM_CAMERA_LOGW("Preview was not enabled, enabling now!\n");
+    rv = StartPreview(aHwHandle);
+    if (rv != OK) {
+      return rv;
+    }
+  }
+
+  // start recording mode
+  hw->mHardware->enableMsgType(CAMERA_MSG_VIDEO_FRAME);
+  DOM_CAMERA_LOGI("Calling hw->startRecording\n");
+  rv = hw->mHardware->startRecording();
+  if (rv != OK) {
+    DOM_CAMERA_LOGE("mHardware->startRecording() failed with status %d", rv);
+  }
+  return rv;
+}
+
+int
+GonkCameraHardware::StopRecording(uint32_t aHwHandle)
+{
+  DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
+  GonkCameraHardware* hw = GetHardware(aHwHandle);
+  if (!hw) {
+    return DEAD_OBJECT;
+  }
+
+  hw->mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
+  hw->mHardware->stopRecording();
+  return OK;
+}
+
+int
+GonkCameraHardware::SetListener(uint32_t aHwHandle, const sp<GonkCameraListener>& aListener)
+{
+  GonkCameraHardware* hw = GetHardware(aHwHandle);
+  if (!hw) {
+    return DEAD_OBJECT;
+  }
+
+  hw->mListener = aListener;
+  return OK;
+}
+
+void
+GonkCameraHardware::ReleaseRecordingFrame(uint32_t aHwHandle, const sp<IMemory>& aFrame)
+{
+  GonkCameraHardware* hw = GetHardware(aHwHandle);
+  if (hw) {
+    hw->mHardware->releaseRecordingFrame(aFrame);
+  }
+}
+
+int
+GonkCameraHardware::StoreMetaDataInBuffers(uint32_t aHwHandle, bool aEnabled)
+{
+  GonkCameraHardware* hw = GetHardware(aHwHandle);
+  if (!hw) {
+    return DEAD_OBJECT;
+  }
+
+  return hw->mHardware->storeMetaDataInBuffers(aEnabled);
+}
--- a/dom/camera/GonkCameraHwMgr.h
+++ b/dom/camera/GonkCameraHwMgr.h
@@ -15,16 +15,18 @@
  */
 
 #ifndef DOM_CAMERA_GONKCAMERAHWMGR_H
 #define DOM_CAMERA_GONKCAMERAHWMGR_H
 
 #include "libcameraservice/CameraHardwareInterface.h"
 #include "binder/IMemory.h"
 #include "mozilla/ReentrantMonitor.h"
+#include "GonkCameraListener.h"
+#include <utils/threads.h>
 
 #include "GonkCameraControl.h"
 #include "CameraCommon.h"
 
 #include "GonkNativeWindow.h"
 
 // config
 #define GIHM_TIMING_RECEIVEFRAME    0
@@ -41,30 +43,36 @@ class GonkCameraHardware : GonkNativeWin
 {
 protected:
   GonkCameraHardware(GonkCamera* aTarget, uint32_t aCamera);
   ~GonkCameraHardware();
   void Init();
 
   static void     DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser);
   static void     NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser);
+  static void     DataCallbackTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory>& aDataPtr, void* aUser);
 
 public:
   virtual void    OnNewFrame() MOZ_OVERRIDE;
 
   static void     ReleaseHandle(uint32_t aHwHandle);
   static uint32_t GetHandle(GonkCamera* aTarget, uint32_t aCamera);
   static int      AutoFocus(uint32_t aHwHandle);
   static void     CancelAutoFocus(uint32_t aHwHandle);
   static int      TakePicture(uint32_t aHwHandle);
   static void     CancelTakePicture(uint32_t aHwHandle);
   static int      StartPreview(uint32_t aHwHandle);
   static void     StopPreview(uint32_t aHwHandle);
   static int      PushParameters(uint32_t aHwHandle, const CameraParameters& aParams);
   static void     PullParameters(uint32_t aHwHandle, CameraParameters& aParams);
+  static int      StartRecording(uint32_t aHwHandle);
+  static int      StopRecording(uint32_t aHwHandle);
+  static int      SetListener(uint32_t aHwHandle, const sp<GonkCameraListener>& aListener);
+  static void     ReleaseRecordingFrame(uint32_t aHwHandle, const sp<IMemory>& aFrame);
+  static int      StoreMetaDataInBuffers(uint32_t aHwHandle, bool aEnabled);
 
 protected:
   static GonkCameraHardware*    sHw;
   static uint32_t               sHwHandle;
 
   static GonkCameraHardware*    GetHardware(uint32_t aHwHandle)
   {
     if (aHwHandle == sHwHandle) {
@@ -88,16 +96,17 @@ protected:
   sp<CameraHardwareInterface>   mHardware;
   GonkCamera*                   mTarget;
   camera_module_t*              mModule;
   sp<ANativeWindow>             mWindow;
 #if GIHM_TIMING_OVERALL
   struct timespec               mStart;
   struct timespec               mAutoFocusStart;
 #endif
+  sp<GonkCameraListener>        mListener;
   bool                          mInitialized;
 
   bool IsInitialized()
   {
     return mInitialized;
   }
 
 private:
new file mode 100644
--- /dev/null
+++ b/dom/camera/GonkCameraListener.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GONK_CAMERA_LISTENER_H
+#define GONK_CAMERA_LISTENER_H
+
+#include <utils/Timers.h>
+#include "libcameraservice/CameraHardwareInterface.h"
+
+namespace android {
+
+// ref-counted object for callbacks
+class GonkCameraListener: virtual public RefBase
+{
+public:
+    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+    virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
+                          camera_frame_metadata_t *metadata) = 0;
+    virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+};
+
+}; // namespace android
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/camera/GonkCameraSource.cpp
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/basictypes.h>
+#include "nsDebug.h"
+#define DOM_CAMERA_LOG_LEVEL        3
+#include "CameraCommon.h"
+#define LOGD DOM_CAMERA_LOGA
+#define LOGV DOM_CAMERA_LOGI
+#define LOGI DOM_CAMERA_LOGI
+#define LOGW DOM_CAMERA_LOGW
+#define LOGE DOM_CAMERA_LOGE
+
+#include <OMX_Component.h>
+#include "GonkCameraSource.h"
+#include "GonkCameraListener.h"
+#include "GonkCameraHwMgr.h"
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+#include <cutils/properties.h>
+
+using namespace mozilla;
+namespace android {
+
+static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
+
+struct GonkCameraSourceListener : public GonkCameraListener {
+    GonkCameraSourceListener(const sp<GonkCameraSource> &source);
+
+    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
+    virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr,
+                          camera_frame_metadata_t *metadata);
+
+    virtual void postDataTimestamp(
+            nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+
+protected:
+    virtual ~GonkCameraSourceListener();
+
+private:
+    wp<GonkCameraSource> mSource;
+
+    GonkCameraSourceListener(const GonkCameraSourceListener &);
+    GonkCameraSourceListener &operator=(const GonkCameraSourceListener &);
+};
+
+GonkCameraSourceListener::GonkCameraSourceListener(const sp<GonkCameraSource> &source)
+    : mSource(source) {
+}
+
+GonkCameraSourceListener::~GonkCameraSourceListener() {
+}
+
+void GonkCameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
+    LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
+}
+
+void GonkCameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
+                                    camera_frame_metadata_t *metadata) {
+    LOGV("postData(%d, ptr:%p, size:%d)",
+         msgType, dataPtr->pointer(), dataPtr->size());
+
+    sp<GonkCameraSource> source = mSource.promote();
+    if (source.get() != NULL) {
+        source->dataCallback(msgType, dataPtr);
+    }
+}
+
+void GonkCameraSourceListener::postDataTimestamp(
+        nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
+
+    sp<GonkCameraSource> source = mSource.promote();
+    if (source.get() != NULL) {
+        source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
+    }
+}
+
+static int32_t getColorFormat(const char* colorFormat) {
+    return OMX_COLOR_FormatYUV420SemiPlanar;
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
+       return OMX_COLOR_FormatYUV420Planar;
+    }
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) {
+       return OMX_COLOR_FormatYUV422SemiPlanar;
+    }
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
+        return OMX_COLOR_FormatYUV420SemiPlanar;
+    }
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
+        return OMX_COLOR_FormatYCbYCr;
+    }
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
+       return OMX_COLOR_Format16bitRGB565;
+    }
+
+    if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
+       return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
+    }
+
+    LOGE("Uknown color format (%s), please add it to "
+         "GonkCameraSource::getColorFormat", colorFormat);
+
+    CHECK_EQ(0, "Unknown color format");
+}
+
+GonkCameraSource *GonkCameraSource::Create(
+    int32_t cameraHandle,
+    Size videoSize,
+    int32_t frameRate,
+    bool storeMetaDataInVideoBuffers) {
+
+    GonkCameraSource *source = new GonkCameraSource(cameraHandle,
+                    videoSize, frameRate,
+                    storeMetaDataInVideoBuffers);
+    return source;
+}
+
+GonkCameraSource::GonkCameraSource(
+    int32_t cameraHandle,
+    Size videoSize,
+    int32_t frameRate,
+    bool storeMetaDataInVideoBuffers)
+    : mCameraFlags(0),
+      mVideoFrameRate(-1),
+      mNumFramesReceived(0),
+      mLastFrameTimestampUs(0),
+      mStarted(false),
+      mNumFramesEncoded(0),
+      mTimeBetweenFrameCaptureUs(0),
+      mFirstFrameTimeUs(0),
+      mNumFramesDropped(0),
+      mNumGlitches(0),
+      mGlitchDurationThresholdUs(200000),
+      mCollectStats(false) {
+    mVideoSize.width  = -1;
+    mVideoSize.height = -1;
+
+    mCameraHandle = cameraHandle;
+
+    mInitCheck = init(
+                    videoSize, frameRate,
+                    storeMetaDataInVideoBuffers);
+    if (mInitCheck != OK) releaseCamera();
+}
+
+status_t GonkCameraSource::initCheck() const {
+    return mInitCheck;
+}
+
+//TODO: Do we need to reimplement isCameraAvailable?
+
+/*
+ * Check to see whether the requested video width and height is one
+ * of the supported sizes.
+ * @param width the video frame width in pixels
+ * @param height the video frame height in pixels
+ * @param suppportedSizes the vector of sizes that we check against
+ * @return true if the dimension (width and height) is supported.
+ */
+static bool isVideoSizeSupported(
+    int32_t width, int32_t height,
+    const Vector<Size>& supportedSizes) {
+
+    LOGV("isVideoSizeSupported");
+    for (size_t i = 0; i < supportedSizes.size(); ++i) {
+        if (width  == supportedSizes[i].width &&
+            height == supportedSizes[i].height) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * If the preview and video output is separate, we only set the
+ * the video size, and applications should set the preview size
+ * to some proper value, and the recording framework will not
+ * change the preview size; otherwise, if the video and preview
+ * output is the same, we need to set the preview to be the same
+ * as the requested video size.
+ *
+ */
+/*
+ * Query the camera to retrieve the supported video frame sizes
+ * and also to see whether CameraParameters::setVideoSize()
+ * is supported or not.
+ * @param params CameraParameters to retrieve the information
+ * @@param isSetVideoSizeSupported retunrs whether method
+ *      CameraParameters::setVideoSize() is supported or not.
+ * @param sizes returns the vector of Size objects for the
+ *      supported video frame sizes advertised by the camera.
+ */
+static void getSupportedVideoSizes(
+    const CameraParameters& params,
+    bool *isSetVideoSizeSupported,
+    Vector<Size>& sizes) {
+
+    *isSetVideoSizeSupported = true;
+    params.getSupportedVideoSizes(sizes);
+    if (sizes.size() == 0) {
+        LOGD("Camera does not support setVideoSize()");
+        params.getSupportedPreviewSizes(sizes);
+        *isSetVideoSizeSupported = false;
+    }
+}
+
+/*
+ * Check whether the camera has the supported color format
+ * @param params CameraParameters to retrieve the information
+ * @return OK if no error.
+ */
+status_t GonkCameraSource::isCameraColorFormatSupported(
+        const CameraParameters& params) {
+    mColorFormat = getColorFormat(params.get(
+            CameraParameters::KEY_VIDEO_FRAME_FORMAT));
+    if (mColorFormat == -1) {
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+/*
+ * Configure the camera to use the requested video size
+ * (width and height) and/or frame rate. If both width and
+ * height are -1, configuration on the video size is skipped.
+ * if frameRate is -1, configuration on the frame rate
+ * is skipped. Skipping the configuration allows one to
+ * use the current camera setting without the need to
+ * actually know the specific values (see Create() method).
+ *
+ * @param params the CameraParameters to be configured
+ * @param width the target video frame width in pixels
+ * @param height the target video frame height in pixels
+ * @param frameRate the target frame rate in frames per second.
+ * @return OK if no error.
+ */
+status_t GonkCameraSource::configureCamera(
+        CameraParameters* params,
+        int32_t width, int32_t height,
+        int32_t frameRate) {
+    LOGV("configureCamera");
+    Vector<Size> sizes;
+    bool isSetVideoSizeSupportedByCamera = true;
+    getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
+    bool isCameraParamChanged = false;
+    if (width != -1 && height != -1) {
+        if (!isVideoSizeSupported(width, height, sizes)) {
+            LOGE("Video dimension (%dx%d) is unsupported", width, height);
+            return BAD_VALUE;
+        }
+        if (isSetVideoSizeSupportedByCamera) {
+            params->setVideoSize(width, height);
+        } else {
+            params->setPreviewSize(width, height);
+        }
+        isCameraParamChanged = true;
+    } else if ((width == -1 && height != -1) ||
+               (width != -1 && height == -1)) {
+        // If one and only one of the width and height is -1
+        // we reject such a request.
+        LOGE("Requested video size (%dx%d) is not supported", width, height);
+        return BAD_VALUE;
+    } else {  // width == -1 && height == -1
+        // Do not configure the camera.
+        // Use the current width and height value setting from the camera.
+    }
+
+    if (frameRate != -1) {
+        CHECK(frameRate > 0 && frameRate <= 120);
+        const char* supportedFrameRates =
+                params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
+        CHECK(supportedFrameRates != NULL);
+        LOGV("Supported frame rates: %s", supportedFrameRates);
+        char buf[4];
+        snprintf(buf, 4, "%d", frameRate);
+        if (strstr(supportedFrameRates, buf) == NULL) {
+            LOGE("Requested frame rate (%d) is not supported: %s",
+                frameRate, supportedFrameRates);
+            return BAD_VALUE;
+        }
+
+        // The frame rate is supported, set the camera to the requested value.
+        params->setPreviewFrameRate(frameRate);
+        isCameraParamChanged = true;
+    } else {  // frameRate == -1
+        // Do not configure the camera.
+        // Use the current frame rate value setting from the camera
+    }
+
+    if (isCameraParamChanged) {
+        // Either frame rate or frame size needs to be changed.
+        if (OK != GonkCameraHardware::PushParameters(mCameraHandle,*params)) {
+            LOGE("Could not change settings."
+                 " Someone else is using camera ?");
+            return -EBUSY;
+        }
+    }
+    return OK;
+}
+
+/*
+ * Check whether the requested video frame size
+ * has been successfully configured or not. If both width and height
+ * are -1, check on the current width and height value setting
+ * is performed.
+ *
+ * @param params CameraParameters to retrieve the information
+ * @param the target video frame width in pixels to check against
+ * @param the target video frame height in pixels to check against
+ * @return OK if no error
+ */
+status_t GonkCameraSource::checkVideoSize(
+        const CameraParameters& params,
+        int32_t width, int32_t height) {
+
+    LOGV("checkVideoSize");
+    // The actual video size is the same as the preview size
+    // if the camera hal does not support separate video and
+    // preview output. In this case, we retrieve the video
+    // size from preview.
+    int32_t frameWidthActual = -1;
+    int32_t frameHeightActual = -1;
+    Vector<Size> sizes;
+    params.getSupportedVideoSizes(sizes);
+    if (sizes.size() == 0) {
+        // video size is the same as preview size
+        params.getPreviewSize(&frameWidthActual, &frameHeightActual);
+    } else {
+        // video size may not be the same as preview
+        params.getVideoSize(&frameWidthActual, &frameHeightActual);
+    }
+    if (frameWidthActual < 0 || frameHeightActual < 0) {
+        LOGE("Failed to retrieve video frame size (%dx%d)",
+                frameWidthActual, frameHeightActual);
+        return UNKNOWN_ERROR;
+    }
+
+    // Check the actual video frame size against the target/requested
+    // video frame size.
+    if (width != -1 && height != -1) {
+        if (frameWidthActual != width || frameHeightActual != height) {
+            LOGE("Failed to set video frame size to %dx%d. "
+                    "The actual video size is %dx%d ", width, height,
+                    frameWidthActual, frameHeightActual);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    // Good now.
+    mVideoSize.width = frameWidthActual;
+    mVideoSize.height = frameHeightActual;
+    return OK;
+}
+
+/*
+ * Check the requested frame rate has been successfully configured or not.
+ * If the target frameRate is -1, check on the current frame rate value
+ * setting is performed.
+ *
+ * @param params CameraParameters to retrieve the information
+ * @param the target video frame rate to check against
+ * @return OK if no error.
+ */
+status_t GonkCameraSource::checkFrameRate(
+        const CameraParameters& params,
+        int32_t frameRate) {
+
+    LOGV("checkFrameRate");
+    int32_t frameRateActual = params.getPreviewFrameRate();
+    if (frameRateActual < 0) {
+        LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
+        return UNKNOWN_ERROR;
+    }
+
+    // Check the actual video frame rate against the target/requested
+    // video frame rate.
+    if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
+        LOGE("Failed to set preview frame rate to %d fps. The actual "
+                "frame rate is %d", frameRate, frameRateActual);
+        return UNKNOWN_ERROR;
+    }
+
+    // Good now.
+    mVideoFrameRate = frameRateActual;
+    return OK;
+}
+
+/*
+ * Initialize the CameraSource to so that it becomes
+ * ready for providing the video input streams as requested.
+ * @param camera the camera object used for the video source
+ * @param cameraId if camera == 0, use camera with this id
+ *      as the video source
+ * @param videoSize the target video frame size. If both
+ *      width and height in videoSize is -1, use the current
+ *      width and heigth settings by the camera
+ * @param frameRate the target frame rate in frames per second.
+ *      if it is -1, use the current camera frame rate setting.
+ * @param storeMetaDataInVideoBuffers request to store meta
+ *      data or real YUV data in video buffers. Request to
+ *      store meta data in video buffers may not be honored
+ *      if the source does not support this feature.
+ *
+ * @return OK if no error.
+ */
+status_t GonkCameraSource::init(
+        Size videoSize,
+        int32_t frameRate,
+        bool storeMetaDataInVideoBuffers) {
+
+    LOGV("init");
+    status_t err = OK;
+    //TODO: need to do something here to check the sanity of camera
+
+    CameraParameters params;
+    GonkCameraHardware::PullParameters(mCameraHandle, params);
+    if ((err = isCameraColorFormatSupported(params)) != OK) {
+        return err;
+    }
+
+    // Set the camera to use the requested video frame size
+    // and/or frame rate.
+    if ((err = configureCamera(&params,
+                    videoSize.width, videoSize.height,
+                    frameRate))) {
+        return err;
+    }
+
+    // Check on video frame size and frame rate.
+    CameraParameters newCameraParams;
+    GonkCameraHardware::PullParameters(mCameraHandle, newCameraParams);
+    if ((err = checkVideoSize(newCameraParams,
+                videoSize.width, videoSize.height)) != OK) {
+        return err;
+    }
+    if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) {
+        return err;
+    }
+
+    // By default, do not store metadata in video buffers
+    mIsMetaDataStoredInVideoBuffers = false;
+    GonkCameraHardware::StoreMetaDataInBuffers(mCameraHandle, false);
+    if (storeMetaDataInVideoBuffers) {
+        if (OK == GonkCameraHardware::StoreMetaDataInBuffers(mCameraHandle, true)) {
+            mIsMetaDataStoredInVideoBuffers = true;
+        }
+    }
+
+    const char *hfr_str = params.get("video-hfr");
+    int32_t hfr = -1;
+    if ( hfr_str != NULL ) {
+      hfr = atoi(hfr_str);
+    }
+    if(hfr < 0) {
+      LOGW("Invalid hfr value(%d) set from app. Disabling HFR.", hfr);
+      hfr = 0;
+    }
+
+    int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
+    if (glitchDurationUs > mGlitchDurationThresholdUs) {
+        mGlitchDurationThresholdUs = glitchDurationUs;
+    }
+
+    const char * k3dFrameArrangement = "3d-frame-format";
+    const char * arrangement = params.get(k3dFrameArrangement);
+    // XXX: just assume left/right for now since that's all the camera supports
+    bool want3D = (arrangement != NULL && !strcmp("left-right", arrangement));
+
+    // XXX: query camera for the stride and slice height
+    // when the capability becomes available.
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType,  MEDIA_MIMETYPE_VIDEO_RAW);
+    mMeta->setInt32(kKeyColorFormat, mColorFormat);
+    mMeta->setInt32(kKeyWidth,       mVideoSize.width);
+    mMeta->setInt32(kKeyHeight,      mVideoSize.height);
+    mMeta->setInt32(kKeyStride,      mVideoSize.width);
+    mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
+    mMeta->setInt32(kKeyFrameRate,   mVideoFrameRate);
+
+    return OK;
+}
+
+GonkCameraSource::~GonkCameraSource() {
+    if (mStarted) {
+        stop();
+    } else if (mInitCheck == OK) {
+        // Camera is initialized but because start() is never called,
+        // the lock on Camera is never released(). This makes sure
+        // Camera's lock is released in this case.
+        // TODO: Don't think I need to do this
+        releaseCamera();
+    }
+}
+
+void GonkCameraSource::startCameraRecording() {
+    LOGV("startCameraRecording");
+    CHECK_EQ(OK, GonkCameraHardware::StartRecording(mCameraHandle));
+}
+
+status_t GonkCameraSource::start(MetaData *meta) {
+    LOGV("start");
+    CHECK(!mStarted);
+    if (mInitCheck != OK) {
+        LOGE("GonkCameraSource is not initialized yet");
+        return mInitCheck;
+    }
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.record-stats", value, NULL)
+        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        mCollectStats = true;
+    }
+
+    mStartTimeUs = 0;
+    int64_t startTimeUs;
+    if (meta && meta->findInt64(kKeyTime, &startTimeUs)) {
+        LOGV("Metadata enabled, startime: %lld us", startTimeUs);
+        mStartTimeUs = startTimeUs;
+    }
+
+    // Register a listener with GonkCameraHardware so that we can get callbacks
+    GonkCameraHardware::SetListener(mCameraHandle, new GonkCameraSourceListener(this));
+
+    startCameraRecording();
+
+    mStarted = true;
+    return OK;
+}
+
+void GonkCameraSource::stopCameraRecording() {
+    LOGV("stopCameraRecording");
+    GonkCameraHardware::StopRecording(mCameraHandle);
+}
+
+void GonkCameraSource::releaseCamera() {
+    LOGV("releaseCamera");
+}
+
+status_t GonkCameraSource::stop() {
+    LOGV("stop: E");
+    Mutex::Autolock autoLock(mLock);
+    mStarted = false;
+    mFrameAvailableCondition.signal();
+
+    releaseQueuedFrames();
+    while (!mFramesBeingEncoded.empty()) {
+        if (NO_ERROR !=
+            mFrameCompleteCondition.waitRelative(mLock,
+                    mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
+            LOGW("Timed out waiting for outstanding frames being encoded: %d",
+                mFramesBeingEncoded.size());
+        }
+    }
+    LOGV("Calling stopCameraRecording");
+    stopCameraRecording();
+    releaseCamera();
+
+    if (mCollectStats) {
+        LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
+                mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
+                mLastFrameTimestampUs - mFirstFrameTimeUs);
+    }
+
+    if (mNumGlitches > 0) {
+        LOGW("%d long delays between neighboring video frames", mNumGlitches);
+    }
+
+    CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
+    LOGV("stop: X");
+    return OK;
+}
+
+void GonkCameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
+    LOGV("releaseRecordingFrame");
+    GonkCameraHardware::ReleaseRecordingFrame(mCameraHandle, frame);
+}
+
+void GonkCameraSource::releaseQueuedFrames() {
+    List<sp<IMemory> >::iterator it;
+    while (!mFramesReceived.empty()) {
+        it = mFramesReceived.begin();
+        releaseRecordingFrame(*it);
+        mFramesReceived.erase(it);
+        ++mNumFramesDropped;
+    }
+}
+
+sp<MetaData> GonkCameraSource::getFormat() {
+    return mMeta;
+}
+
+void GonkCameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
+    releaseRecordingFrame(frame);
+}
+
+void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) {
+    LOGV("signalBufferReturned: %p", buffer->data());
+    Mutex::Autolock autoLock(mLock);
+    for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
+         it != mFramesBeingEncoded.end(); ++it) {
+        if ((*it)->pointer() ==  buffer->data()) {
+            releaseOneRecordingFrame((*it));
+            mFramesBeingEncoded.erase(it);
+            ++mNumFramesEncoded;
+            buffer->setObserver(0);
+            buffer->release();
+            mFrameCompleteCondition.signal();
+            return;
+        }
+    }
+    CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+}
+
+status_t GonkCameraSource::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    LOGV("read");
+
+    *buffer = NULL;
+
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode mode;
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    sp<IMemory> frame;
+    int64_t frameTime;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+        while (mStarted && mFramesReceived.empty()) {
+            if (NO_ERROR !=
+                mFrameAvailableCondition.waitRelative(mLock,
+                    mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
+                //TODO: check sanity of camera?
+                LOGW("Timed out waiting for incoming camera video frames: %lld us",
+                    mLastFrameTimestampUs);
+            }
+        }
+        if (!mStarted) {
+            return OK;
+        }
+        frame = *mFramesReceived.begin();
+        mFramesReceived.erase(mFramesReceived.begin());
+
+        frameTime = *mFrameTimes.begin();
+        mFrameTimes.erase(mFrameTimes.begin());
+        mFramesBeingEncoded.push_back(frame);
+        *buffer = new MediaBuffer(frame->pointer(), frame->size());
+        (*buffer)->setObserver(this);
+        (*buffer)->add_ref();
+        (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
+    }
+    return OK;
+}
+
+void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
+        int32_t msgType, const sp<IMemory> &data) {
+    LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
+    //LOGV("dataCallbackTimestamp: data %x size %d", data->pointer(), data->size());
+    Mutex::Autolock autoLock(mLock);
+    if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
+        LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
+        releaseOneRecordingFrame(data);
+        return;
+    }
+
+    if (mNumFramesReceived > 0) {
+        CHECK(timestampUs > mLastFrameTimestampUs);
+        if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
+            ++mNumGlitches;
+        }
+    }
+
+    // May need to skip frame or modify timestamp. Currently implemented
+    // by the subclass GonkCameraSourceTimeLapse.
+    if (skipCurrentFrame(timestampUs)) {
+        releaseOneRecordingFrame(data);
+        return;
+    }
+
+    mLastFrameTimestampUs = timestampUs;
+    if (mNumFramesReceived == 0) {
+        mFirstFrameTimeUs = timestampUs;
+        // Initial delay
+        if (mStartTimeUs > 0) {
+            if (timestampUs < mStartTimeUs) {
+                // Frame was captured before recording was started
+                // Drop it without updating the statistical data.
+                releaseOneRecordingFrame(data);
+                return;
+            }
+            mStartTimeUs = timestampUs - mStartTimeUs;
+        }
+    }
+    ++mNumFramesReceived;
+
+    CHECK(data != NULL && data->size() > 0);
+    mFramesReceived.push_back(data);
+    int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
+    mFrameTimes.push_back(timeUs);
+    LOGV("initial delay: %lld, current time stamp: %lld",
+        mStartTimeUs, timeUs);
+    mFrameAvailableCondition.signal();
+}
+
+bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {
+    LOGV("isMetaDataStoredInVideoBuffers");
+    return mIsMetaDataStoredInVideoBuffers;
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/dom/camera/GonkCameraSource.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GONK_CAMERA_SOURCE_H_
+
+#define GONK_CAMERA_SOURCE_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <camera/CameraParameters.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class IMemory;
+class GonkCameraSourceListener;
+
+class GonkCameraSource : public MediaSource, public MediaBufferObserver {
+public:
+
+    static GonkCameraSource *Create(int32_t cameraHandle,
+                                    Size videoSize,
+                                    int32_t frameRate,
+                                    bool storeMetaDataInVideoBuffers = false);
+
+    virtual ~GonkCameraSource();
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+    /**
+     * Check whether a GonkCameraSource object is properly initialized.
+     * Must call this method before stop().
+     * @return OK if initialization has successfully completed.
+     */
+    virtual status_t initCheck() const;
+
+    /**
+     * Returns the MetaData associated with the GonkCameraSource,
+     * including:
+     * kKeyColorFormat: YUV color format of the video frames
+     * kKeyWidth, kKeyHeight: dimension (in pixels) of the video frames
+     * kKeySampleRate: frame rate in frames per second
+     * kKeyMIMEType: always fixed to be MEDIA_MIMETYPE_VIDEO_RAW
+     */
+    virtual sp<MetaData> getFormat();
+
+    /**
+     * Tell whether this camera source stores meta data or real YUV
+     * frame data in video buffers.
+     *
+     * @return true if meta data is stored in the video
+     *      buffers; false if real YUV data is stored in
+     *      the video buffers.
+     */
+    bool isMetaDataStoredInVideoBuffers() const;
+
+    virtual void signalBufferReturned(MediaBuffer* buffer);
+
+protected:
+
+    enum CameraFlags {
+        FLAGS_SET_CAMERA = 1L << 0,
+        FLAGS_HOT_CAMERA = 1L << 1,
+    };
+
+    int32_t  mCameraFlags;
+    Size     mVideoSize;
+    int32_t  mVideoFrameRate;
+    int32_t  mColorFormat;
+    status_t mInitCheck;
+
+    sp<MetaData> mMeta;
+
+    int64_t mStartTimeUs;
+    int32_t mNumFramesReceived;
+    int64_t mLastFrameTimestampUs;
+    bool mStarted;
+    int32_t mNumFramesEncoded;
+
+    // Time between capture of two frames.
+    int64_t mTimeBetweenFrameCaptureUs;
+
+    GonkCameraSource(int32_t cameraHandle,
+                 Size videoSize, int32_t frameRate,
+                 bool storeMetaDataInVideoBuffers = false);
+
+    virtual void startCameraRecording();
+    virtual void stopCameraRecording();
+    virtual void releaseRecordingFrame(const sp<IMemory>& frame);
+
+    // Returns true if need to skip the current frame.
+    // Called from dataCallbackTimestamp.
+    virtual bool skipCurrentFrame(int64_t timestampUs) {return false;}
+
+    friend class GonkCameraSourceListener;
+    // Callback called when still camera raw data is available.
+    virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {}
+
+    virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
+            const sp<IMemory> &data);
+
+private:
+
+    Mutex mLock;
+    Condition mFrameAvailableCondition;
+    Condition mFrameCompleteCondition;
+    List<sp<IMemory> > mFramesReceived;
+    List<sp<IMemory> > mFramesBeingEncoded;
+    List<int64_t> mFrameTimes;
+
+    int64_t mFirstFrameTimeUs;
+    int32_t mNumFramesDropped;
+    int32_t mNumGlitches;
+    int64_t mGlitchDurationThresholdUs;
+    bool mCollectStats;
+    bool mIsMetaDataStoredInVideoBuffers;
+    int32_t mCameraHandle;
+
+    void releaseQueuedFrames();
+    void releaseOneRecordingFrame(const sp<IMemory>& frame);
+
+    status_t init(Size videoSize, int32_t frameRate,
+                  bool storeMetaDataInVideoBuffers);
+    status_t isCameraColorFormatSupported(const CameraParameters& params);
+    status_t configureCamera(CameraParameters* params,
+                    int32_t width, int32_t height,
+                    int32_t frameRate);
+
+    status_t checkVideoSize(const CameraParameters& params,
+                    int32_t width, int32_t height);
+
+    status_t checkFrameRate(const CameraParameters& params,
+                    int32_t frameRate);
+
+    void releaseCamera();
+
+    GonkCameraSource(const GonkCameraSource &);
+    GonkCameraSource &operator=(const GonkCameraSource &);
+};
+
+}  // namespace android
+
+#endif  // GONK_CAMERA_SOURCE_H_
new file mode 100644
--- /dev/null
+++ b/dom/camera/GonkRecorder.cpp
@@ -0,0 +1,1629 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GonkRecorder"
+
+#include <utils/Log.h>
+#include <media/AudioParameter.h>
+#include "GonkRecorder.h"
+
+#include <media/stagefright/AudioSource.h>
+#include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <OMX.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/MediaProfiles.h>
+#include <utils/String8.h>
+
+#include <utils/Errors.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <system/audio.h>
+
+#include "ARTPWriter.h"
+
+#include <cutils/properties.h>
+#include "GonkCameraSource.h"
+
+namespace android {
+
+static sp<IOMX> sOMX = NULL;
+static sp<IOMX> GetOMX() {
+  if(sOMX.get() == NULL) {
+    sOMX = new OMX;
+    }
+  return sOMX;
+}
+
+GonkRecorder::GonkRecorder()
+    : mWriter(NULL),
+      mOutputFd(-1),
+      mAudioSource(AUDIO_SOURCE_CNT),
+      mVideoSource(VIDEO_SOURCE_LIST_END),
+      mStarted(false),
+      mDisableAudio(false) {
+
+    LOGV("Constructor");
+    reset();
+}
+
+GonkRecorder::~GonkRecorder() {
+    LOGV("Destructor");
+    stop();
+}
+
+status_t GonkRecorder::init() {
+    LOGV("init");
+    return OK;
+}
+
+status_t GonkRecorder::setAudioSource(audio_source_t as) {
+    LOGV("setAudioSource: %d", as);
+    if (as < AUDIO_SOURCE_DEFAULT ||
+        as >= AUDIO_SOURCE_CNT) {
+        LOGE("Invalid audio source: %d", as);
+        return BAD_VALUE;
+    }
+
+    if (mDisableAudio) {
+        return OK;
+    }
+
+    if (as == AUDIO_SOURCE_DEFAULT) {
+        mAudioSource = AUDIO_SOURCE_MIC;
+    } else {
+        mAudioSource = as;
+    }
+
+    return OK;
+}
+
+status_t GonkRecorder::setVideoSource(video_source vs) {
+    LOGV("setVideoSource: %d", vs);
+    if (vs < VIDEO_SOURCE_DEFAULT ||
+        vs >= VIDEO_SOURCE_LIST_END) {
+        LOGE("Invalid video source: %d", vs);
+        return BAD_VALUE;
+    }
+
+    if (vs == VIDEO_SOURCE_DEFAULT) {
+        mVideoSource = VIDEO_SOURCE_CAMERA;
+    } else {
+        mVideoSource = vs;
+    }
+
+    return OK;
+}
+
+status_t GonkRecorder::setOutputFormat(output_format of) {
+    LOGV("setOutputFormat: %d", of);
+    if (of < OUTPUT_FORMAT_DEFAULT ||
+        of >= OUTPUT_FORMAT_LIST_END) {
+        LOGE("Invalid output format: %d", of);
+        return BAD_VALUE;
+    }
+
+    if (of == OUTPUT_FORMAT_DEFAULT) {
+        mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
+    } else {
+        mOutputFormat = of;
+    }
+
+    return OK;
+}
+
+status_t GonkRecorder::setAudioEncoder(audio_encoder ae) {
+    LOGV("setAudioEncoder: %d", ae);
+    if (ae < AUDIO_ENCODER_DEFAULT ||
+        ae >= AUDIO_ENCODER_LIST_END) {
+        LOGE("Invalid audio encoder: %d", ae);
+        return BAD_VALUE;
+    }
+
+    if (mDisableAudio) {
+        return OK;
+    }
+
+    if (ae == AUDIO_ENCODER_DEFAULT) {
+        mAudioEncoder = AUDIO_ENCODER_AMR_NB;
+    } else {
+        mAudioEncoder = ae;
+    }
+
+    return OK;
+}
+
+status_t GonkRecorder::setVideoEncoder(video_encoder ve) {
+    LOGV("setVideoEncoder: %d", ve);
+    if (ve < VIDEO_ENCODER_DEFAULT ||
+        ve >= VIDEO_ENCODER_LIST_END) {
+        LOGE("Invalid video encoder: %d", ve);
+        return BAD_VALUE;
+    }
+
+    if (ve == VIDEO_ENCODER_DEFAULT) {
+        mVideoEncoder = VIDEO_ENCODER_H263;
+    } else {
+        mVideoEncoder = ve;
+    }
+
+    return OK;
+}
+
+status_t GonkRecorder::setVideoSize(int width, int height) {
+    LOGV("setVideoSize: %dx%d", width, height);
+    if (width <= 0 || height <= 0) {
+        LOGE("Invalid video size: %dx%d", width, height);
+        return BAD_VALUE;
+    }
+
+    // Additional check on the dimension will be performed later
+    mVideoWidth = width;
+    mVideoHeight = height;
+
+    return OK;
+}
+
+status_t GonkRecorder::setVideoFrameRate(int frames_per_second) {
+    LOGV("setVideoFrameRate: %d", frames_per_second);
+    if ((frames_per_second <= 0 && frames_per_second != -1) ||
+        frames_per_second > 120) {
+        LOGE("Invalid video frame rate: %d", frames_per_second);
+        return BAD_VALUE;
+    }
+
+    // Additional check on the frame rate will be performed later
+    mFrameRate = frames_per_second;
+
+    return OK;
+}
+
+status_t GonkRecorder::setOutputFile(const char *path) {
+    LOGE("setOutputFile(const char*) must not be called");
+    // We don't actually support this at all, as the media_server process
+    // no longer has permissions to create files.
+
+    return -EPERM;
+}
+
+status_t GonkRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
+    LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
+    // These don't make any sense, do they?
+    CHECK_EQ(offset, 0);
+    CHECK_EQ(length, 0);
+
+    if (fd < 0) {
+        LOGE("Invalid file descriptor: %d", fd);
+        return -EBADF;
+    }
+
+    if (mOutputFd >= 0) {
+        ::close(mOutputFd);
+    }
+    mOutputFd = dup(fd);
+
+    return OK;
+}
+
+// Attempt to parse an int64 literal optionally surrounded by whitespace,
+// returns true on success, false otherwise.
+static bool safe_strtoi64(const char *s, int64_t *val) {
+    char *end;
+
+    // It is lame, but according to man page, we have to set errno to 0
+    // before calling strtoll().
+    errno = 0;
+    *val = strtoll(s, &end, 10);
+
+    if (end == s || errno == ERANGE) {
+        return false;
+    }
+
+    // Skip trailing whitespace
+    while (isspace(*end)) {
+        ++end;
+    }
+
+    // For a successful return, the string must contain nothing but a valid
+    // int64 literal optionally surrounded by whitespace.
+
+    return *end == '\0';
+}
+
+// Return true if the value is in [0, 0x007FFFFFFF]
+static bool safe_strtoi32(const char *s, int32_t *val) {
+    int64_t temp;
+    if (safe_strtoi64(s, &temp)) {
+        if (temp >= 0 && temp <= 0x007FFFFFFF) {
+            *val = static_cast<int32_t>(temp);
+            return true;
+        }
+    }
+    return false;
+}
+
+// Trim both leading and trailing whitespace from the given string.
+static void TrimString(String8 *s) {
+    size_t num_bytes = s->bytes();
+    const char *data = s->string();
+
+    size_t leading_space = 0;
+    while (leading_space < num_bytes && isspace(data[leading_space])) {
+        ++leading_space;
+    }
+
+    size_t i = num_bytes;
+    while (i > leading_space && isspace(data[i - 1])) {
+        --i;
+    }
+
+    s->setTo(String8(&data[leading_space], i - leading_space));
+}
+
+status_t GonkRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
+    LOGV("setParamAudioSamplingRate: %d", sampleRate);
+    if (sampleRate <= 0) {
+        LOGE("Invalid audio sampling rate: %d", sampleRate);
+        return BAD_VALUE;
+    }
+
+    // Additional check on the sample rate will be performed later.
+    mSampleRate = sampleRate;
+    return OK;
+}
+
+status_t GonkRecorder::setParamAudioNumberOfChannels(int32_t channels) {
+    LOGV("setParamAudioNumberOfChannels: %d", channels);
+    if (channels <= 0 || channels >= 3) {
+        LOGE("Invalid number of audio channels: %d", channels);
+        return BAD_VALUE;
+    }
+
+    // Additional check on the number of channels will be performed later.
+    mAudioChannels = channels;
+    return OK;
+}
+
+status_t GonkRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
+    LOGV("setParamAudioEncodingBitRate: %d", bitRate);
+    if (bitRate <= 0) {
+        LOGE("Invalid audio encoding bit rate: %d", bitRate);
+        return BAD_VALUE;
+    }
+
+    // The target bit rate may not be exactly the same as the requested.
+    // It depends on many factors, such as rate control, and the bit rate
+    // range that a specific encoder supports. The mismatch between the
+    // the target and requested bit rate will NOT be treated as an error.
+    mAudioBitRate = bitRate;
+    return OK;
+}
+
+status_t GonkRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
+    LOGV("setParamVideoEncodingBitRate: %d", bitRate);
+    if (bitRate <= 0) {
+        LOGE("Invalid video encoding bit rate: %d", bitRate);
+        return BAD_VALUE;
+    }
+
+    // The target bit rate may not be exactly the same as the requested.
+    // It depends on many factors, such as rate control, and the bit rate
+    // range that a specific encoder supports. The mismatch between the
+    // the target and requested bit rate will NOT be treated as an error.
+    mVideoBitRate = bitRate;
+    return OK;
+}
+
+// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
+status_t GonkRecorder::setParamVideoRotation(int32_t degrees) {
+    LOGV("setParamVideoRotation: %d", degrees);
+    if (degrees < 0 || degrees % 90 != 0) {
+        LOGE("Unsupported video rotation angle: %d", degrees);
+        return BAD_VALUE;
+    }
+    mRotationDegrees = degrees % 360;
+    return OK;
+}
+
+status_t GonkRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
+    LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
+
+    // This is meant for backward compatibility for MediaRecorder.java
+    if (timeUs <= 0) {
+        LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
+        timeUs = 0; // Disable the duration limit for zero or negative values.
+    } else if (timeUs <= 100000LL) {  // XXX: 100 milli-seconds
+        LOGE("Max file duration is too short: %lld us", timeUs);
+        return BAD_VALUE;
+    }
+
+    if (timeUs <= 15 * 1000000LL) {
+        LOGW("Target duration (%lld us) too short to be respected", timeUs);
+    }
+    mMaxFileDurationUs = timeUs;
+    return OK;
+}
+
+status_t GonkRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
+    LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
+
+    // This is meant for backward compatibility for MediaRecorder.java
+    if (bytes <= 0) {
+        LOGW("Max file size is not positive: %lld bytes. "
+             "Disabling file size limit.", bytes);
+        bytes = 0; // Disable the file size limit for zero or negative values.
+    } else if (bytes <= 1024) {  // XXX: 1 kB
+        LOGE("Max file size is too small: %lld bytes", bytes);
+        return BAD_VALUE;
+    }
+
+    if (bytes <= 100 * 1024) {
+        LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
+    }
+
+    if (bytes >= 0xffffffffLL) {
+        LOGW("Target file size (%lld bytes) too larger than supported, clip to 4GB", bytes);
+        bytes = 0xffffffffLL;
+    }
+
+    mMaxFileSizeBytes = bytes;
+    return OK;
+}
+
+status_t GonkRecorder::setParamInterleaveDuration(int32_t durationUs) {
+    LOGV("setParamInterleaveDuration: %d", durationUs);
+    if (durationUs <= 500000) {           //  500 ms
+        // If interleave duration is too small, it is very inefficient to do
+        // interleaving since the metadata overhead will count for a significant
+        // portion of the saved contents
+        LOGE("Audio/video interleave duration is too small: %d us", durationUs);
+        return BAD_VALUE;
+    } else if (durationUs >= 10000000) {  // 10 seconds
+        // If interleaving duration is too large, it can cause the recording
+        // session to use too much memory since we have to save the output
+        // data before we write them out
+        LOGE("Audio/video interleave duration is too large: %d us", durationUs);
+        return BAD_VALUE;
+    }
+    mInterleaveDurationUs = durationUs;
+    return OK;
+}
+
+// If seconds <  0, only the first frame is I frame, and rest are all P frames
+// If seconds == 0, all frames are encoded as I frames. No P frames
+// If seconds >  0, it is the time spacing (seconds) between 2 neighboring I frames
+status_t GonkRecorder::setParamVideoIFramesInterval(int32_t seconds) {
+    LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
+    mIFramesIntervalSec = seconds;
+    return OK;
+}
+
+status_t GonkRecorder::setParam64BitFileOffset(bool use64Bit) {
+    LOGV("setParam64BitFileOffset: %s",
+        use64Bit? "use 64 bit file offset": "use 32 bit file offset");
+    mUse64BitFileOffset = use64Bit;
+    return OK;
+}
+
+status_t GonkRecorder::setParamVideoCameraId(int32_t cameraId) {
+    LOGV("setParamVideoCameraId: %d", cameraId);
+    if (cameraId < 0) {
+        return BAD_VALUE;
+    }
+    mCameraId = cameraId;
+    return OK;
+}
+
+status_t GonkRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
+    LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
+    if (timeDurationUs < 20000) {  // Infeasible if shorter than 20 ms?
+        LOGE("Tracking time duration too short: %lld us", timeDurationUs);
+        return BAD_VALUE;
+    }
+    mTrackEveryTimeDurationUs = timeDurationUs;
+    return OK;
+}
+
+status_t GonkRecorder::setParamVideoEncoderProfile(int32_t profile) {
+    LOGV("setParamVideoEncoderProfile: %d", profile);
+
+    // Additional check will be done later when we load the encoder.
+    // For now, we are accepting values defined in OpenMAX IL.
+    mVideoEncoderProfile = profile;
+    return OK;
+}
+
+status_t GonkRecorder::setParamVideoEncoderLevel(int32_t level) {
+    LOGV("setParamVideoEncoderLevel: %d", level);
+
+    // Additional check will be done later when we load the encoder.
+    // For now, we are accepting values defined in OpenMAX IL.
+    mVideoEncoderLevel = level;
+    return OK;
+}
+
+status_t GonkRecorder::setParamMovieTimeScale(int32_t timeScale) {
+    LOGV("setParamMovieTimeScale: %d", timeScale);
+
+    // The range is set to be the same as the audio's time scale range
+    // since audio's time scale has a wider range.
+    if (timeScale < 600 || timeScale > 96000) {
+        LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
+        return BAD_VALUE;
+    }
+    mMovieTimeScale = timeScale;
+    return OK;
+}
+
+status_t GonkRecorder::setParamVideoTimeScale(int32_t timeScale) {
+    LOGV("setParamVideoTimeScale: %d", timeScale);
+
+    // 60000 is chosen to make sure that each video frame from a 60-fps
+    // video has 1000 ticks.
+    if (timeScale < 600 || timeScale > 60000) {
+        LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
+        return BAD_VALUE;
+    }
+    mVideoTimeScale = timeScale;
+    return OK;
+}
+
+status_t GonkRecorder::setParamAudioTimeScale(int32_t timeScale) {
+    LOGV("setParamAudioTimeScale: %d", timeScale);
+
+    // 96000 Hz is the highest sampling rate support in AAC.
+    if (timeScale < 600 || timeScale > 96000) {
+        LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
+        return BAD_VALUE;
+    }
+    mAudioTimeScale = timeScale;
+    return OK;
+}
+
+status_t GonkRecorder::setParamGeoDataLongitude(
+    int64_t longitudex10000) {
+
+    if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
+        return BAD_VALUE;
+    }
+    mLongitudex10000 = longitudex10000;
+    return OK;
+}
+
+status_t GonkRecorder::setParamGeoDataLatitude(
+    int64_t latitudex10000) {
+
+    if (latitudex10000 > 900000 || latitudex10000 < -900000) {
+        return BAD_VALUE;
+    }
+    mLatitudex10000 = latitudex10000;
+    return OK;
+}
+
+status_t GonkRecorder::setParameter(
+        const String8 &key, const String8 &value) {
+    LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
+    if (key == "max-duration") {
+        int64_t max_duration_ms;
+        if (safe_strtoi64(value.string(), &max_duration_ms)) {
+            return setParamMaxFileDurationUs(1000LL * max_duration_ms);
+        }
+    } else if (key == "max-filesize") {
+        int64_t max_filesize_bytes;
+        if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
+            return setParamMaxFileSizeBytes(max_filesize_bytes);
+        }
+    } else if (key == "interleave-duration-us") {
+        int32_t durationUs;
+        if (safe_strtoi32(value.string(), &durationUs)) {
+            return setParamInterleaveDuration(durationUs);
+        }
+    } else if (key == "param-movie-time-scale") {
+        int32_t timeScale;
+        if (safe_strtoi32(value.string(), &timeScale)) {
+            return setParamMovieTimeScale(timeScale);
+        }
+    } else if (key == "param-use-64bit-offset") {
+        int32_t use64BitOffset;
+        if (safe_strtoi32(value.string(), &use64BitOffset)) {
+            return setParam64BitFileOffset(use64BitOffset != 0);
+        }
+    } else if (key == "param-geotag-longitude") {
+        int64_t longitudex10000;
+        if (safe_strtoi64(value.string(), &longitudex10000)) {
+            return setParamGeoDataLongitude(longitudex10000);
+        }
+    } else if (key == "param-geotag-latitude") {
+        int64_t latitudex10000;
+        if (safe_strtoi64(value.string(), &latitudex10000)) {
+            return setParamGeoDataLatitude(latitudex10000);
+        }
+    } else if (key == "param-track-time-status") {
+        int64_t timeDurationUs;
+        if (safe_strtoi64(value.string(), &timeDurationUs)) {
+            return setParamTrackTimeStatus(timeDurationUs);
+        }
+    } else if (key == "audio-param-sampling-rate") {
+        int32_t sampling_rate;
+        if (safe_strtoi32(value.string(), &sampling_rate)) {
+            return setParamAudioSamplingRate(sampling_rate);
+        }
+    } else if (key == "audio-param-number-of-channels") {
+        int32_t number_of_channels;
+        if (safe_strtoi32(value.string(), &number_of_channels)) {
+            return setParamAudioNumberOfChannels(number_of_channels);
+        }
+    } else if (key == "audio-param-encoding-bitrate") {
+        int32_t audio_bitrate;
+        if (safe_strtoi32(value.string(), &audio_bitrate)) {
+            return setParamAudioEncodingBitRate(audio_bitrate);
+        }
+    } else if (key == "audio-param-time-scale") {
+        int32_t timeScale;
+        if (safe_strtoi32(value.string(), &timeScale)) {
+            return setParamAudioTimeScale(timeScale);
+        }
+    } else if (key == "video-param-encoding-bitrate") {
+        int32_t video_bitrate;
+        if (safe_strtoi32(value.string(), &video_bitrate)) {
+            return setParamVideoEncodingBitRate(video_bitrate);
+        }
+    } else if (key == "video-param-rotation-angle-degrees") {
+        int32_t degrees;
+        if (safe_strtoi32(value.string(), &degrees)) {
+            return setParamVideoRotation(degrees);
+        }
+    } else if (key == "video-param-i-frames-interval") {
+        int32_t seconds;
+        if (safe_strtoi32(value.string(), &seconds)) {
+            return setParamVideoIFramesInterval(seconds);
+        }
+    } else if (key == "video-param-encoder-profile") {
+        int32_t profile;
+        if (safe_strtoi32(value.string(), &profile)) {
+            return setParamVideoEncoderProfile(profile);
+        }
+    } else if (key == "video-param-encoder-level") {
+        int32_t level;
+        if (safe_strtoi32(value.string(), &level)) {
+            return setParamVideoEncoderLevel(level);
+        }
+    } else if (key == "video-param-camera-id") {
+        int32_t cameraId;
+        if (safe_strtoi32(value.string(), &cameraId)) {
+            return setParamVideoCameraId(cameraId);
+        }
+    } else if (key == "video-param-time-scale") {
+        int32_t timeScale;
+        if (safe_strtoi32(value.string(), &timeScale)) {
+            return setParamVideoTimeScale(timeScale);
+        }
+    } else {
+        LOGE("setParameter: failed to find key %s", key.string());
+    }
+    return BAD_VALUE;
+}
+
+status_t GonkRecorder::setParameters(const String8 &params) {
+    LOGV("setParameters: %s", params.string());
+    const char *cparams = params.string();
+    const char *key_start = cparams;
+    for (;;) {
+        const char *equal_pos = strchr(key_start, '=');
+        if (equal_pos == NULL) {
+            LOGE("Parameters %s miss a value", cparams);
+            return BAD_VALUE;
+        }
+        String8 key(key_start, equal_pos - key_start);
+        TrimString(&key);
+        if (key.length() == 0) {
+            LOGE("Parameters %s contains an empty key", cparams);
+            return BAD_VALUE;
+        }
+        const char *value_start = equal_pos + 1;
+        const char *semicolon_pos = strchr(value_start, ';');
+        String8 value;
+        if (semicolon_pos == NULL) {
+            value.setTo(value_start);
+        } else {
+            value.setTo(value_start, semicolon_pos - value_start);
+        }
+        if (setParameter(key, value) != OK) {
+            return BAD_VALUE;
+        }
+        if (semicolon_pos == NULL) {
+            break;  // Reaches the end
+        }
+        key_start = semicolon_pos + 1;
+    }
+    return OK;
+}
+
+status_t GonkRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
+    mListener = listener;
+
+    return OK;
+}
+
+status_t GonkRecorder::prepare() {
+  LOGV(" %s E", __func__ );
+
+  if(mVideoSource != VIDEO_SOURCE_LIST_END && mVideoEncoder != VIDEO_ENCODER_LIST_END && mVideoHeight && mVideoWidth &&             /*Video recording*/
+         (mMaxFileDurationUs <=0 ||             /*Max duration is not set*/
+         (mVideoHeight * mVideoWidth < 720 * 1280 && mMaxFileDurationUs > 30*60*1000*1000) ||
+         (mVideoHeight * mVideoWidth >= 720 * 1280 && mMaxFileDurationUs > 10*60*1000*1000))) {
+    /*Above Check can be further optimized for lower resolutions to reduce file size*/
+    LOGV("File is huge so setting 64 bit file offsets");
+    setParam64BitFileOffset(true);
+  }
+  LOGV(" %s X", __func__ );
+  return OK;
+}
+
+status_t GonkRecorder::start() {
+    CHECK(mOutputFd >= 0);
+
+    if (mWriter != NULL) {
+        LOGE("File writer is not available");
+        return UNKNOWN_ERROR;
+    }
+
+    status_t status = OK;
+
+    switch (mOutputFormat) {
+        case OUTPUT_FORMAT_DEFAULT:
+        case OUTPUT_FORMAT_THREE_GPP:
+        case OUTPUT_FORMAT_MPEG_4:
+            status = startMPEG4Recording();
+            break;
+
+        case OUTPUT_FORMAT_AMR_NB:
+        case OUTPUT_FORMAT_AMR_WB:
+            status = startAMRRecording();
+            break;
+
+        case OUTPUT_FORMAT_MPEG2TS:
+            status = startMPEG2TSRecording();
+		    break;
+        default:
+            LOGE("Unsupported output file format: %d", mOutputFormat);
+            status = UNKNOWN_ERROR;
+            break;
+    }
+
+    if ((status == OK) && (!mStarted)) {
+        mStarted = true;
+    }
+
+    return status;
+}
+
+sp<MediaSource> GonkRecorder::createAudioSource() {
+
+    sp<AudioSource> audioSource =
+        new AudioSource(
+                mAudioSource,
+                mSampleRate,
+                mAudioChannels);
+
+    status_t err = audioSource->initCheck();
+
+    if (err != OK) {
+        LOGE("audio source is not initialized");
+        return NULL;
+    }
+
+    sp<MetaData> encMeta = new MetaData;
+    const char *mime;
+    switch (mAudioEncoder) {
+        case AUDIO_ENCODER_AMR_NB:
+        case AUDIO_ENCODER_DEFAULT:
+            mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+            break;
+        case AUDIO_ENCODER_AMR_WB:
+            mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+            break;
+        case AUDIO_ENCODER_AAC:
+            mime = MEDIA_MIMETYPE_AUDIO_AAC;
+            break;
+        default:
+            LOGE("Unknown audio encoder: %d", mAudioEncoder);
+            return NULL;
+    }
+    encMeta->setCString(kKeyMIMEType, mime);
+
+    int32_t maxInputSize;
+    CHECK(audioSource->getFormat()->findInt32(
+                kKeyMaxInputSize, &maxInputSize));
+
+    encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
+    encMeta->setInt32(kKeyChannelCount, mAudioChannels);
+    encMeta->setInt32(kKeySampleRate, mSampleRate);
+    encMeta->setInt32(kKeyBitRate, mAudioBitRate);
+    if (mAudioTimeScale > 0) {
+        encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+    }
+
+    // use direct OMX interface instead of connecting to
+    // mediaserver over binder calls
+    sp<MediaSource> audioEncoder =
+        OMXCodec::Create(GetOMX(), encMeta,
+                         true /* createEncoder */, audioSource);
+    mAudioSourceNode = audioSource;
+
+    return audioEncoder;
+}
+
+status_t GonkRecorder::startAMRRecording() {
+    CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
+          mOutputFormat == OUTPUT_FORMAT_AMR_WB);
+
+    if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
+        if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
+            mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
+            LOGE("Invalid encoder %d used for AMRNB recording",
+                    mAudioEncoder);
+            return BAD_VALUE;
+        }
+    } else {  // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
+        if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
+            LOGE("Invlaid encoder %d used for AMRWB recording",
+                    mAudioEncoder);
+            return BAD_VALUE;
+        }
+    }
+
+    mWriter = new AMRWriter(mOutputFd);
+    status_t status = startRawAudioRecording();
+    if (status != OK) {
+        mWriter.clear();
+        mWriter = NULL;
+    }
+    return status;
+}
+
+status_t GonkRecorder::startRawAudioRecording() {
+    if (mAudioSource >= AUDIO_SOURCE_CNT) {
+        LOGE("Invalid audio source: %d", mAudioSource);
+        return BAD_VALUE;
+    }
+
+    status_t status = BAD_VALUE;
+    if (OK != (status = checkAudioEncoderCapabilities())) {
+        return status;
+    }
+
+    sp<MediaSource> audioEncoder = createAudioSource();
+    if (audioEncoder == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    CHECK(mWriter != 0);
+    mWriter->addSource(audioEncoder);
+
+    if (mMaxFileDurationUs != 0) {
+        mWriter->setMaxFileDuration(mMaxFileDurationUs);
+    }
+    if (mMaxFileSizeBytes != 0) {
+        mWriter->setMaxFileSize(mMaxFileSizeBytes);
+    }
+    mWriter->setListener(mListener);
+    mWriter->start();
+
+    return OK;
+}
+
+status_t GonkRecorder::startMPEG2TSRecording() {
+    CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
+
+    sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
+
+    if (mAudioSource != AUDIO_SOURCE_CNT) {
+        if (mAudioEncoder != AUDIO_ENCODER_AAC) {
+            return ERROR_UNSUPPORTED;
+        }
+
+        status_t err = setupAudioEncoder(writer);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    if (mVideoSource < VIDEO_SOURCE_LIST_END) {
+        if (mVideoEncoder != VIDEO_ENCODER_H264) {
+            return ERROR_UNSUPPORTED;
+        }
+
+        sp<MediaSource> mediaSource;
+        status_t err = setupMediaSource(&mediaSource);
+        if (err != OK) {
+            return err;
+        }
+
+        sp<MediaSource> encoder;
+        err = setupVideoEncoder(mediaSource, mVideoBitRate, &encoder);
+
+        if (err != OK) {
+            return err;
+        }
+
+        writer->addSource(encoder);
+    }
+
+    if (mMaxFileDurationUs != 0) {
+        writer->setMaxFileDuration(mMaxFileDurationUs);
+    }
+
+    if (mMaxFileSizeBytes != 0) {
+        writer->setMaxFileSize(mMaxFileSizeBytes);
+    }
+
+    mWriter = writer;
+
+    return mWriter->start();
+}
+
+void GonkRecorder::clipVideoFrameRate() {
+    LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
+    int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.fps.min", mVideoEncoder);
+    int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.fps.max", mVideoEncoder);
+    if (mFrameRate < minFrameRate && mFrameRate != -1) {
+        LOGW("Intended video encoding frame rate (%d fps) is too small"
+             " and will be set to (%d fps)", mFrameRate, minFrameRate);
+        mFrameRate = minFrameRate;
+    } else if (mFrameRate > maxFrameRate) {
+        LOGW("Intended video encoding frame rate (%d fps) is too large"
+             " and will be set to (%d fps)", mFrameRate, maxFrameRate);
+        mFrameRate = maxFrameRate;
+    }
+}
+
+void GonkRecorder::clipVideoBitRate() {
+    LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
+    int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.bps.min", mVideoEncoder);
+    int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.bps.max", mVideoEncoder);
+    if (mVideoBitRate < minBitRate) {
+        LOGW("Intended video encoding bit rate (%d bps) is too small"
+             " and will be set to (%d bps)", mVideoBitRate, minBitRate);
+        mVideoBitRate = minBitRate;
+    } else if (mVideoBitRate > maxBitRate) {
+        LOGW("Intended video encoding bit rate (%d bps) is too large"
+             " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
+        mVideoBitRate = maxBitRate;
+    }
+}
+
+void GonkRecorder::clipVideoFrameWidth() {
+    LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
+    int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.width.min", mVideoEncoder);
+    int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.width.max", mVideoEncoder);
+    if (mVideoWidth < minFrameWidth) {
+        LOGW("Intended video encoding frame width (%d) is too small"
+             " and will be set to (%d)", mVideoWidth, minFrameWidth);
+        mVideoWidth = minFrameWidth;
+    } else if (mVideoWidth > maxFrameWidth) {
+        LOGW("Intended video encoding frame width (%d) is too large"
+             " and will be set to (%d)", mVideoWidth, maxFrameWidth);
+        mVideoWidth = maxFrameWidth;
+    }
+}
+
+status_t GonkRecorder::checkVideoEncoderCapabilities() {
+        // Dont clip for time lapse capture as encoder will have enough
+        // time to encode because of slow capture rate of time lapse.
+        clipVideoBitRate();
+        clipVideoFrameRate();
+        clipVideoFrameWidth();
+        clipVideoFrameHeight();
+        setDefaultProfileIfNecessary();
+    return OK;
+}
+
+// Set to use AVC baseline profile if the encoding parameters matches
+// CAMCORDER_QUALITY_LOW profile; this is for the sake of MMS service.
+void GonkRecorder::setDefaultProfileIfNecessary() {
+    LOGV("setDefaultProfileIfNecessary");
+
+    camcorder_quality quality = CAMCORDER_QUALITY_LOW;
+
+    int64_t durationUs   = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "duration", mCameraId, quality) * 1000000LL;
+
+    int fileFormat       = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "file.format", mCameraId, quality);
+
+    int videoCodec       = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "vid.codec", mCameraId, quality);
+
+    int videoBitRate     = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "vid.bps", mCameraId, quality);
+
+    int videoFrameRate   = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "vid.fps", mCameraId, quality);
+
+    int videoFrameWidth  = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "vid.width", mCameraId, quality);
+
+    int videoFrameHeight = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "vid.height", mCameraId, quality);
+
+    int audioCodec       = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "aud.codec", mCameraId, quality);
+
+    int audioBitRate     = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "aud.bps", mCameraId, quality);
+
+    int audioSampleRate  = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "aud.hz", mCameraId, quality);
+
+    int audioChannels    = mEncoderProfiles->getCamcorderProfileParamByName(
+                                "aud.ch", mCameraId, quality);
+
+    if (durationUs == mMaxFileDurationUs &&
+        fileFormat == mOutputFormat &&
+        videoCodec == mVideoEncoder &&
+        videoBitRate == mVideoBitRate &&
+        videoFrameRate == mFrameRate &&
+        videoFrameWidth == mVideoWidth &&
+        videoFrameHeight == mVideoHeight &&
+        audioCodec == mAudioEncoder &&
+        audioBitRate == mAudioBitRate &&
+        audioSampleRate == mSampleRate &&
+        audioChannels == mAudioChannels) {
+        if (videoCodec == VIDEO_ENCODER_H264) {
+            LOGI("Force to use AVC baseline profile");
+            setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline);
+        }
+    }
+}
+
+status_t GonkRecorder::checkAudioEncoderCapabilities() {
+    clipAudioBitRate();
+    clipAudioSampleRate();
+    clipNumberOfAudioChannels();
+    return OK;
+}
+
+void GonkRecorder::clipAudioBitRate() {
+    LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
+
+    int minAudioBitRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.bps.min", mAudioEncoder);
+    if (mAudioBitRate < minAudioBitRate) {
+        LOGW("Intended audio encoding bit rate (%d) is too small"
+            " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
+        mAudioBitRate = minAudioBitRate;
+    }
+
+    int maxAudioBitRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.bps.max", mAudioEncoder);
+    if (mAudioBitRate > maxAudioBitRate) {
+        LOGW("Intended audio encoding bit rate (%d) is too large"
+            " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
+        mAudioBitRate = maxAudioBitRate;
+    }
+}
+
+void GonkRecorder::clipAudioSampleRate() {
+    LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
+
+    int minSampleRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.hz.min", mAudioEncoder);
+    if (mSampleRate < minSampleRate) {
+        LOGW("Intended audio sample rate (%d) is too small"
+            " and will be set to (%d)", mSampleRate, minSampleRate);
+        mSampleRate = minSampleRate;
+    }
+
+    int maxSampleRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.hz.max", mAudioEncoder);
+    if (mSampleRate > maxSampleRate) {
+        LOGW("Intended audio sample rate (%d) is too large"
+            " and will be set to (%d)", mSampleRate, maxSampleRate);
+        mSampleRate = maxSampleRate;
+    }
+}
+
+void GonkRecorder::clipNumberOfAudioChannels() {
+    LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
+
+    int minChannels =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.ch.min", mAudioEncoder);
+    if (mAudioChannels < minChannels) {
+        LOGW("Intended number of audio channels (%d) is too small"
+            " and will be set to (%d)", mAudioChannels, minChannels);
+        mAudioChannels = minChannels;
+    }
+
+    int maxChannels =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.ch.max", mAudioEncoder);
+    if (mAudioChannels > maxChannels) {
+        LOGW("Intended number of audio channels (%d) is too large"
+            " and will be set to (%d)", mAudioChannels, maxChannels);
+        mAudioChannels = maxChannels;
+    }
+}
+
+void GonkRecorder::clipVideoFrameHeight() {
+    LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
+    int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.height.min", mVideoEncoder);
+    int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
+                        "enc.vid.height.max", mVideoEncoder);
+    if (mVideoHeight < minFrameHeight) {
+        LOGW("Intended video encoding frame height (%d) is too small"
+             " and will be set to (%d)", mVideoHeight, minFrameHeight);
+        mVideoHeight = minFrameHeight;
+    } else if (mVideoHeight > maxFrameHeight) {
+        LOGW("Intended video encoding frame height (%d) is too large"
+             " and will be set to (%d)", mVideoHeight, maxFrameHeight);
+        mVideoHeight = maxFrameHeight;
+    }
+}
+
+// Set up the appropriate MediaSource depending on the chosen option
+status_t GonkRecorder::setupMediaSource(
+                      sp<MediaSource> *mediaSource) {
+    if (mVideoSource == VIDEO_SOURCE_DEFAULT
+            || mVideoSource == VIDEO_SOURCE_CAMERA) {
+        sp<GonkCameraSource> cameraSource;
+        status_t err = setupCameraSource(&cameraSource);
+        if (err != OK) {
+            return err;
+        }
+        *mediaSource = cameraSource;
+    } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
+        return BAD_VALUE;
+    } else {
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t GonkRecorder::setupCameraSource(
+        sp<GonkCameraSource> *cameraSource) {
+    status_t err = OK;
+    if ((err = checkVideoEncoderCapabilities()) != OK) {
+        return err;
+    }
+    Size videoSize;
+    videoSize.width = mVideoWidth;
+    videoSize.height = mVideoHeight;
+    bool useMeta = true;
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("debug.camcorder.disablemeta", value, NULL) &&
+            atoi(value)) {
+      useMeta = false;
+    }
+
+    *cameraSource = GonkCameraSource::Create(
+                mCameraHandle, videoSize, mFrameRate, useMeta);
+    if (*cameraSource == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    if ((*cameraSource)->initCheck() != OK) {
+        (*cameraSource).clear();
+        *cameraSource = NULL;
+        return NO_INIT;
+    }
+
+    // When frame rate is not set, the actual frame rate will be set to
+    // the current frame rate being used.
+    if (mFrameRate == -1) {
+        int32_t frameRate = 0;
+        CHECK ((*cameraSource)->getFormat()->findInt32(
+                    kKeyFrameRate, &frameRate));
+        LOGI("Frame rate is not explicitly set. Use the current frame "
+             "rate (%d fps)", frameRate);
+        mFrameRate = frameRate;
+    }
+
+    CHECK(mFrameRate != -1);
+
+    mIsMetaDataStoredInVideoBuffers =
+        (*cameraSource)->isMetaDataStoredInVideoBuffers();
+
+    return OK;
+}
+
+status_t GonkRecorder::setupVideoEncoder(
+        sp<MediaSource> cameraSource,
+        int32_t videoBitRate,
+        sp<MediaSource> *source) {
+    source->clear();
+
+    sp<MetaData> enc_meta = new MetaData;
+    enc_meta->setInt32(kKeyBitRate, videoBitRate);
+    enc_meta->setInt32(kKeyFrameRate, mFrameRate);
+
+    switch (mVideoEncoder) {
+        case VIDEO_ENCODER_H263:
+            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+            break;
+
+        case VIDEO_ENCODER_MPEG_4_SP:
+            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+            break;
+
+        case VIDEO_ENCODER_H264:
+            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+            break;
+
+        default:
+            CHECK(!"Should not be here, unsupported video encoding.");
+            break;
+    }
+
+    sp<MetaData> meta = cameraSource->getFormat();
+
+    int32_t width, height, stride, sliceHeight, colorFormat;
+    CHECK(meta->findInt32(kKeyWidth, &width));
+    CHECK(meta->findInt32(kKeyHeight, &height));
+    CHECK(meta->findInt32(kKeyStride, &stride));
+    CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+    CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
+
+    enc_meta->setInt32(kKeyWidth, width);
+    enc_meta->setInt32(kKeyHeight, height);
+    enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
+    enc_meta->setInt32(kKeyStride, stride);
+    enc_meta->setInt32(kKeySliceHeight, sliceHeight);
+    enc_meta->setInt32(kKeyColorFormat, colorFormat);
+    if (mVideoTimeScale > 0) {
+        enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+    }
+
+    /*
+     * can set profile from the app as a parameter.
+     * For the mean time, set from shell
+     */
+
+    char value[PROPERTY_VALUE_MAX];
+    bool customProfile = false;
+
+    if (property_get("encoder.video.profile", value, NULL) > 0) {
+        customProfile = true;
+    }
+
+    if (customProfile) {
+        switch ( mVideoEncoder ) {
+        case VIDEO_ENCODER_H264:
+            if (strncmp("base", value, 4) == 0) {
+                mVideoEncoderProfile = OMX_VIDEO_AVCProfileBaseline;
+                LOGI("H264 Baseline Profile");
+            }
+            else if (strncmp("main", value, 4) == 0) {
+                mVideoEncoderProfile = OMX_VIDEO_AVCProfileMain;
+                LOGI("H264 Main Profile");
+            }
+            else if (strncmp("high", value, 4) == 0) {
+                mVideoEncoderProfile = OMX_VIDEO_AVCProfileHigh;
+                LOGI("H264 High Profile");
+            }
+            else {
+               LOGW("Unsupported H264 Profile");
+            }
+            break;
+        case VIDEO_ENCODER_MPEG_4_SP:
+            if (strncmp("simple", value, 5) == 0 ) {
+                mVideoEncoderProfile = OMX_VIDEO_MPEG4ProfileSimple;
+                LOGI("MPEG4 Simple profile");
+            }
+            else if (strncmp("asp", value, 3) == 0 ) {
+                mVideoEncoderProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple;
+                LOGI("MPEG4 Advanced Simple Profile");
+            }
+            else {
+                LOGW("Unsupported MPEG4 Profile");
+            }
+            break;
+        default:
+            LOGW("No custom profile support for other codecs");
+            break;
+        }
+    }
+
+    if (mVideoEncoderProfile != -1) {
+        enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
+    }
+    if (mVideoEncoderLevel != -1) {
+        enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
+    }
+
+    uint32_t encoder_flags = 0;
+    if (mIsMetaDataStoredInVideoBuffers) {
+        LOGW("Camera source supports metadata mode, create OMXCodec for metadata");
+        encoder_flags |= OMXCodec::kHardwareCodecsOnly;
+        encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
+        encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
+    }
+
+    sp<MediaSource> encoder = OMXCodec::Create(
+            GetOMX(),
+            enc_meta,
+            true /* createEncoder */, cameraSource,
+            NULL, encoder_flags);
+    if (encoder == NULL) {
+        LOGW("Failed to create the encoder");
+        // When the encoder fails to be created, we need
+        // release the camera source due to the camera's lock
+        // and unlock mechanism.
+        cameraSource->stop();
+        return UNKNOWN_ERROR;
+    }
+
+    *source = encoder;
+
+    return OK;
+}
+
+status_t GonkRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
+    status_t status = BAD_VALUE;
+    if (OK != (status = checkAudioEncoderCapabilities())) {
+        return status;
+    }
+
+    switch(mAudioEncoder) {
+        case AUDIO_ENCODER_AMR_NB:
+        case AUDIO_ENCODER_AMR_WB:
+        case AUDIO_ENCODER_AAC:
+            break;
+
+        default:
+            LOGE("Unsupported audio encoder: %d", mAudioEncoder);
+            return UNKNOWN_ERROR;
+    }
+
+    sp<MediaSource> audioEncoder = createAudioSource();
+    if (audioEncoder == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    writer->addSource(audioEncoder);
+    return OK;
+}
+
+status_t GonkRecorder::setupMPEG4Recording(
+        int outputFd,
+        int32_t videoWidth, int32_t videoHeight,
+        int32_t videoBitRate,
+        int32_t *totalBitRate,
+        sp<MediaWriter> *mediaWriter) {
+    mediaWriter->clear();
+    *totalBitRate = 0;
+    status_t err = OK;
+    sp<MediaWriter> writer = new MPEG4Writer(outputFd);
+
+    if (mVideoSource < VIDEO_SOURCE_LIST_END) {
+
+        sp<MediaSource> mediaSource;
+        err = setupMediaSource(&mediaSource);
+        if (err != OK) {
+            return err;
+        }
+
+        sp<MediaSource> encoder;
+        err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);
+        if (err != OK) {
+            return err;
+        }
+
+        writer->addSource(encoder);
+        *totalBitRate += videoBitRate;
+    }
+
+    // Audio source is added at the end if it exists.
+    // This help make sure that the "recoding" sound is suppressed for
+    // camcorder applications in the recorded files.
+    if (mAudioSource != AUDIO_SOURCE_CNT) {
+        err = setupAudioEncoder(writer);
+        if (err != OK) return err;
+        *totalBitRate += mAudioBitRate;
+    }
+
+    if (mInterleaveDurationUs > 0) {
+        reinterpret_cast<MPEG4Writer *>(writer.get())->
+            setInterleaveDuration(mInterleaveDurationUs);
+    }
+    if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
+        reinterpret_cast<MPEG4Writer *>(writer.get())->
+            setGeoData(mLatitudex10000, mLongitudex10000);
+    }
+    if (mMaxFileDurationUs != 0) {
+        writer->setMaxFileDuration(mMaxFileDurationUs);
+    }
+    if (mMaxFileSizeBytes != 0) {
+        writer->setMaxFileSize(mMaxFileSizeBytes);
+    }
+
+    mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
+    if (mStartTimeOffsetMs > 0) {
+        reinterpret_cast<MPEG4Writer *>(writer.get())->
+            setStartTimeOffsetMs(mStartTimeOffsetMs);
+    }
+
+    writer->setListener(mListener);
+    *mediaWriter = writer;
+    return OK;
+}
+
+void GonkRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
+        sp<MetaData> *meta) {
+    (*meta)->setInt64(kKeyTime, startTimeUs);
+    (*meta)->setInt32(kKeyFileType, mOutputFormat);
+    (*meta)->setInt32(kKeyBitRate, totalBitRate);
+    (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
+    if (mMovieTimeScale > 0) {
+        (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
+    }
+    if (mTrackEveryTimeDurationUs > 0) {
+        (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
+    }
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("debug.camcorder.rotation", value, 0) > 0 && atoi(value) >= 0) {
+        mRotationDegrees = atoi(value);
+        LOGI("Setting rotation to %d", mRotationDegrees );
+    }
+
+    if (mRotationDegrees != 0) {
+        (*meta)->setInt32(kKeyRotation, mRotationDegrees);
+    }
+}
+
+status_t GonkRecorder::startMPEG4Recording() {
+    int32_t totalBitRate;
+    status_t err = setupMPEG4Recording(
+            mOutputFd, mVideoWidth, mVideoHeight,
+            mVideoBitRate, &totalBitRate, &mWriter);
+    if (err != OK) {
+        return err;
+    }
+
+    //systemTime() doesn't give correct time because
+    //HAVE_POSIX_CLOCKS is not defined for utils/Timers.cpp
+    //so, using clock_gettime directly
+#include <time.h>
+    struct timespec t;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    int64_t startTimeUs = int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+    startTimeUs = startTimeUs / 1000;
+    sp<MetaData> meta = new MetaData;
+    setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
+
+    err = mWriter->start(meta.get());
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
+status_t GonkRecorder::pause() {
+    LOGV("pause");
+    if (mWriter == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    mWriter->pause();
+
+    if (mStarted) {
+        mStarted = false;
+    }
+
+
+    return OK;
+}
+
+status_t GonkRecorder::stop() {
+    LOGV("stop");
+    status_t err = OK;
+
+    if (mWriter != NULL) {
+        err = mWriter->stop();
+        mWriter.clear();
+    }
+
+    if (mOutputFd >= 0) {
+        ::close(mOutputFd);
+        mOutputFd = -1;
+    }
+
+    if (mStarted) {
+        mStarted = false;
+    }
+
+
+    return err;
+}
+
+status_t GonkRecorder::close() {
+    LOGV("close");
+    stop();
+
+    return OK;
+}
+
+status_t GonkRecorder::reset() {
+    LOGV("reset");
+    stop();
+
+    // No audio or video source by default
+    mAudioSource = AUDIO_SOURCE_CNT;
+    mVideoSource = VIDEO_SOURCE_LIST_END;
+
+    // Default parameters
+    mOutputFormat  = OUTPUT_FORMAT_THREE_GPP;
+    mAudioEncoder  = AUDIO_ENCODER_AMR_NB;
+    mVideoEncoder  = VIDEO_ENCODER_H263;
+    mVideoWidth    = 176;
+    mVideoHeight   = 144;
+    mFrameRate     = -1;
+    mVideoBitRate  = 192000;
+    mSampleRate    = 8000;
+    mAudioChannels = 1;
+    mAudioBitRate  = 12200;
+    mInterleaveDurationUs = 0;
+    mIFramesIntervalSec = 2;
+    mAudioSourceNode = 0;
+    mUse64BitFileOffset = false;
+    mMovieTimeScale  = -1;
+    mAudioTimeScale  = -1;
+    mVideoTimeScale  = -1;
+    mCameraId        = 0;
+    mStartTimeOffsetMs = -1;
+    mVideoEncoderProfile = -1;
+    mVideoEncoderLevel   = -1;
+    mMaxFileDurationUs = 0;
+    mMaxFileSizeBytes = 0;
+    mTrackEveryTimeDurationUs = 0;
+    mIsMetaDataStoredInVideoBuffers = false;
+    mEncoderProfiles = MediaProfiles::getInstance();
+    mRotationDegrees = 0;
+    mLatitudex10000 = -3600000;
+    mLongitudex10000 = -3600000;
+
+    mOutputFd = -1;
+    mCameraHandle = -1;
+    //TODO: May need to register a listener eventually
+    //if someone is interested in recorder events for now
+    //default to no listener registered
+    mListener = NULL;
+
+    // Disable Audio Encoding
+    char value[PROPERTY_VALUE_MAX];
+    property_get("camcorder.debug.disableaudio", value, "0");
+    if(atoi(value)) mDisableAudio = true;
+
+    return OK;
+}
+
+status_t GonkRecorder::getMaxAmplitude(int *max) {
+    LOGV("getMaxAmplitude");
+
+    if (max == NULL) {
+        LOGE("Null pointer argument");
+        return BAD_VALUE;
+    }
+
+    if (mAudioSourceNode != 0) {
+        *max = mAudioSourceNode->getMaxAmplitude();
+    } else {
+        *max = 0;
+    }
+
+    return OK;
+}
+
+status_t GonkRecorder::dump(
+        int fd, const Vector<String16>& args) const {
+    LOGV("dump");
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    if (mWriter != 0) {
+        mWriter->dump(fd, args);
+    } else {
+        snprintf(buffer, SIZE, "   No file writer\n");
+        result.append(buffer);
+    }
+    snprintf(buffer, SIZE, "   Recorder: %p\n", this);
+    snprintf(buffer, SIZE, "   Output file (fd %d):\n", mOutputFd);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File format: %d\n", mOutputFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file size (bytes): %lld\n", mMaxFileSizeBytes);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file duration (us): %lld\n", mMaxFileDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Interleave duration (us): %d\n", mInterleaveDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Audio\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mAudioSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mAudioEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mAudioBitRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Sampling rate (hz): %d\n", mSampleRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Number of channels: %d\n", mAudioChannels);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Video\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mVideoSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera Id: %d\n", mCameraId);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera Handle: %d\n", mCameraHandle);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Start time offset (ms): %d\n", mStartTimeOffsetMs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mVideoEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder profile: %d\n", mVideoEncoderProfile);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder level: %d\n", mVideoEncoderLevel);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     I frames interval (s): %d\n", mIFramesIntervalSec);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame rate (fps): %d\n", mFrameRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mVideoBitRate);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return OK;
+}
+
+status_t GonkRecorder::setCameraHandle(int32_t handle) {
+  if (handle < 0) {
+    return BAD_VALUE;
+  }
+  mCameraHandle = handle;
+  return OK;
+}
+
+}  // namespace android
new file mode 100644
--- /dev/null
+++ b/dom/camera/GonkRecorder.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GONK_RECORDER_H_
+
+#define GONK_RECORDER_H_
+
+#include <media/mediarecorder.h>
+#include <camera/CameraParameters.h>
+#include <utils/String8.h>
+
+#include <system/audio.h>
+
+namespace android {
+
+class GonkCameraSource;
+struct MediaSource;
+struct MediaWriter;
+class MetaData;
+struct AudioSource;
+class MediaProfiles;
+
+struct GonkRecorder {
+    GonkRecorder();
+    virtual ~GonkRecorder();
+
+    virtual status_t init();
+    virtual status_t setAudioSource(audio_source_t as);
+    virtual status_t setVideoSource(video_source vs);
+    virtual status_t setOutputFormat(output_format of);
+    virtual status_t setAudioEncoder(audio_encoder ae);
+    virtual status_t setVideoEncoder(video_encoder ve);
+    virtual status_t setVideoSize(int width, int height);
+    virtual status_t setVideoFrameRate(int frames_per_second);
+    virtual status_t setOutputFile(const char *path);
+    virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
+    virtual status_t setParameters(const String8& params);
+    virtual status_t setCameraHandle(int32_t handle);
+    virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
+    virtual status_t prepare();
+    virtual status_t start();
+    virtual status_t pause();
+    virtual status_t stop();
+    virtual status_t close();
+    virtual status_t reset();
+    virtual status_t getMaxAmplitude(int *max);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
+    // Querying a SurfaceMediaSourcer
+
+private:
+    sp<IMediaRecorderClient> mListener;
+    sp<MediaWriter> mWriter;
+    int mOutputFd;
+    sp<AudioSource> mAudioSourceNode;
+
+    audio_source_t mAudioSource;
+    video_source mVideoSource;
+    output_format mOutputFormat;
+    audio_encoder mAudioEncoder;
+    video_encoder mVideoEncoder;
+    bool mUse64BitFileOffset;
+    int32_t mVideoWidth, mVideoHeight;
+    int32_t mFrameRate;
+    int32_t mVideoBitRate;
+    int32_t mAudioBitRate;
+    int32_t mAudioChannels;
+    int32_t mSampleRate;
+    int32_t mInterleaveDurationUs;
+    int32_t mIFramesIntervalSec;
+    int32_t mCameraId;
+    int32_t mVideoEncoderProfile;
+    int32_t mVideoEncoderLevel;
+    int32_t mMovieTimeScale;
+    int32_t mVideoTimeScale;
+    int32_t mAudioTimeScale;
+    int64_t mMaxFileSizeBytes;
+    int64_t mMaxFileDurationUs;
+    int64_t mTrackEveryTimeDurationUs;
+    int32_t mRotationDegrees;  // Clockwise
+    int32_t mLatitudex10000;
+    int32_t mLongitudex10000;
+    int32_t mStartTimeOffsetMs;
+
+    String8 mParams;
+
+    bool mIsMetaDataStoredInVideoBuffers;
+    MediaProfiles *mEncoderProfiles;
+
+    bool mStarted;
+    // Needed when GLFrames are encoded.
+    // An <ISurfaceTexture> pointer
+    // will be sent to the client side using which the
+    // frame buffers will be queued and dequeued
+    bool mDisableAudio;
+    int32_t mCameraHandle;
+
+    status_t setupMPEG4Recording(
+        int outputFd,
+        int32_t videoWidth, int32_t videoHeight,
+        int32_t videoBitRate,
+        int32_t *totalBitRate,
+        sp<MediaWriter> *mediaWriter);
+    void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
+        sp<MetaData> *meta);
+    status_t startMPEG4Recording();
+    status_t startAMRRecording();
+    status_t startRawAudioRecording();
+    status_t startMPEG2TSRecording();
+    sp<MediaSource> createAudioSource();
+    status_t checkVideoEncoderCapabilities();
+    status_t checkAudioEncoderCapabilities();
+    // Generic MediaSource set-up. Returns the appropriate
+    // source (CameraSource or SurfaceMediaSource)
+    // depending on the videosource type
+    status_t setupMediaSource(sp<MediaSource> *mediaSource);
+    status_t setupCameraSource(sp<GonkCameraSource> *cameraSource);
+    // setup the surfacemediasource for the encoder
+
+    status_t setupAudioEncoder(const sp<MediaWriter>& writer);
+    status_t setupVideoEncoder(
+            sp<MediaSource> cameraSource,
+            int32_t videoBitRate,
+            sp<MediaSource> *source);
+
+    // Encoding parameter handling utilities
+    status_t setParameter(const String8 &key, const String8 &value);
+    status_t setParamAudioEncodingBitRate(int32_t bitRate);
+    status_t setParamAudioNumberOfChannels(int32_t channles);
+    status_t setParamAudioSamplingRate(int32_t sampleRate);
+    status_t setParamAudioTimeScale(int32_t timeScale);
+    status_t setParamVideoEncodingBitRate(int32_t bitRate);
+    status_t setParamVideoIFramesInterval(int32_t seconds);
+    status_t setParamVideoEncoderProfile(int32_t profile);
+    status_t setParamVideoEncoderLevel(int32_t level);
+    status_t setParamVideoCameraId(int32_t cameraId);
+    status_t setParamVideoTimeScale(int32_t timeScale);
+    status_t setParamVideoRotation(int32_t degrees);
+    status_t setParamTrackTimeStatus(int64_t timeDurationUs);
+    status_t setParamInterleaveDuration(int32_t durationUs);
+    status_t setParam64BitFileOffset(bool use64BitFileOffset);
+    status_t setParamMaxFileDurationUs(int64_t timeUs);
+    status_t setParamMaxFileSizeBytes(int64_t bytes);
+    status_t setParamMovieTimeScale(int32_t timeScale);
+    status_t setParamGeoDataLongitude(int64_t longitudex10000);
+    status_t setParamGeoDataLatitude(int64_t latitudex10000);
+    void clipVideoBitRate();
+    void clipVideoFrameRate();
+    void clipVideoFrameWidth();
+    void clipVideoFrameHeight();
+    void clipAudioBitRate();
+    void clipAudioSampleRate();
+    void clipNumberOfAudioChannels();
+    void setDefaultProfileIfNecessary();
+
+    GonkRecorder(const GonkRecorder &);
+    GonkRecorder &operator=(const GonkRecorder &);
+};
+
+}  // namespace android
+
+#endif  // GONK_RECORDER_H_
--- a/dom/camera/ICameraControl.h
+++ b/dom/camera/ICameraControl.h
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DOM_CAMERA_ICAMERACONTROL_H
 #define DOM_CAMERA_ICAMERACONTROL_H
 
 #include "jsapi.h"
+#include "nsIDOMDeviceStorage.h"
 #include "nsIDOMCameraManager.h"
 #include "DictionaryHelpers.h"
 #include "CameraCommon.h"
 
 namespace mozilla {
 
 using namespace dom;
 
@@ -21,18 +22,19 @@ class ICameraControl
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ICameraControl)
 
   virtual nsresult GetPreviewStream(CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
   virtual nsresult StartPreview(DOMCameraPreview* aDOMPreview) = 0;
   virtual void StopPreview() = 0;
   virtual nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
   virtual nsresult TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
-  virtual nsresult StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
+  virtual nsresult StartRecording(nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
   virtual nsresult StopRecording() = 0;
+  virtual nsresult GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
 
   virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0;
   virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0;
   virtual nsresult Set(uint32_t aKey, double aValue) = 0;
   virtual nsresult Get(uint32_t aKey, double* aValue) = 0;
   virtual nsresult Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit) = 0;
   virtual nsresult Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue) = 0;
   virtual nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue) = 0;
--- a/dom/camera/Makefile.in
+++ b/dom/camera/Makefile.in
@@ -27,16 +27,19 @@ CPPSRCS = \
   $(NULL)
 
 ifeq ($(MOZ_B2G_CAMERA),1)
 CPPSRCS += \
   GonkCameraManager.cpp \
   GonkCameraControl.cpp \
   GonkCameraHwMgr.cpp \
   GonkNativeWindow.cpp \
+  GonkRecorder.cpp \
+  GonkCameraSource.cpp \
+  AudioParameter.cpp \
   $(NULL)
 else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += \
   FallbackCameraManager.cpp \
   FallbackCameraControl.cpp \
   GonkNativeWindow.cpp \
   $(NULL)
 else
new file mode 100644
--- /dev/null
+++ b/dom/camera/README
@@ -0,0 +1,28 @@
+This README file details from where some of the camcorder source files were derived from and how to apply the provided patch file to get the updated files for B2G.
+---------------------------------
+
+Following is the list of B2G files which were derived from an android ics_chocolate build. It also shows the corresponding locations where the original source files can be found:
+
+GonkRecoder.cpp:
+https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmediaplayerservice/StagefrightRecorder.cpp;hb=ef1672482a9c2b88d8017927df68144fee42626c
+
+GonkRecorder.h:
+https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmediaplayerservice/StagefrightRecorder.h;hb=e3682213bcd3fe43b059e00f0fe4dbebc3f3c35d
+
+GonkCameraSource.cpp:
+https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libstagefright/CameraSource.cpp;hb=7fa677babfee9c241a131b22c9c1c5ab512ef2d2
+
+GonkCameraSource.h:
+https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=include/media/stagefright/CameraSource.h;hb=96af14d9b013496accf40a85a66fefcba3ac0111
+
+AudioParameter.cpp:
+https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmedia/AudioParameter.cpp;hb=4dc22e77cfd2a1c3671e5646ee87c5e4c15596a0
+
+GonkCameraListener.h:
+https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=include/camera/Camera.h;hb=796f35e408d9dca386f90d8fbde80471ac011fa6
+
+There were quite a few changes done to the above listed sources to support camcorder on B2G platform.
+update.patch lists the changes on top of the original files.
+update.sh shell script copies the files from an android tree and applies the patch to get updated files for B2G.
+
+
--- a/dom/camera/nsIDOMCameraManager.idl
+++ b/dom/camera/nsIDOMCameraManager.idl
@@ -1,15 +1,16 @@
 #include "domstubs.idl"
 
 #include "nsIDOMMediaStream.idl"
 #include "nsIDOMDOMRequest.idl"
 
 
 interface nsIDOMBlob;
+interface nsIDOMDeviceStorage;
 
 /* Used to set the dimensions of a captured picture,
    a preview stream, a video capture stream, etc. */
 dictionary CameraSize {
     unsigned long width;
     unsigned long height;
 };
 
@@ -103,20 +104,18 @@ interface nsICameraCapabilities : nsISup
     readonly attribute jsval        zoomRatios;
 
     /* an array of objects with 'height' and 'width' properties
        supported for video recording */
     [implicit_jscontext]
     readonly attribute jsval        videoSizes;
 };
 
-/*
-    These properties only affect the captured image;
-    invalid property settings are ignored.
-*/
+/* These properties only affect the captured image;
+   invalid property settings are ignored. */
 dictionary CameraPictureOptions
 {
     /* an object with a combination of 'height' and 'width' properties
        chosen from nsICameraCapabilities.pictureSizes */
     jsval     pictureSize;
 
     /* one of the file formats chosen from
        nsICameraCapabilities.fileFormats */
@@ -142,16 +141,24 @@ dictionary CameraPictureOptions
         available/desired.
 
         'altitude' is in metres; 'timestamp' is UTC, in seconds from
         January 1, 1970.
     */
     jsval     position;
 };
 
+/* These properties affect video recording. */
+dictionary CameraRecordingOptions
+{
+    long width;
+    long height;
+    long rotation;
+};
+
 [scriptable, function, uuid(0444a687-4bc9-462c-8246-5423f0fe46a4)]
 interface nsICameraPreviewStreamCallback : nsISupports
 {
     void handleEvent(in nsIDOMMediaStream stream);
 };
 
 [scriptable, function, uuid(6baa4ac7-9c25-4c48-9bb0-5193b38b9b0a)]
 interface nsICameraAutoFocusCallback : nsISupports
@@ -160,20 +167,20 @@ interface nsICameraAutoFocusCallback : n
 };
 
 [scriptable, function, uuid(17af779e-cb6f-4ca5-890c-06468ff82e4f)]
 interface nsICameraTakePictureCallback : nsISupports
 {
     void handleEvent(in nsIDOMBlob picture);
 };
 
-[scriptable, function, uuid(ac43f123-529c-48d3-84dd-ad206b7aca9b)]
+[scriptable, function, uuid(89a762f8-581b-410a-ad86-e2bd2113ad82)]
 interface nsICameraStartRecordingCallback : nsISupports
 {
-    void handleEvent(in nsIDOMMediaStream stream);
+    void handleEvent();
 };
 
 [scriptable, function, uuid(fb80db71-e315-42f0-9ea9-dd3dd312ed70)]
 interface nsICameraShutterCallback : nsISupports
 {
     void handleEvent();
 };
 
@@ -182,17 +189,17 @@ interface nsICameraErrorCallback : nsISu
 {
     void handleEvent(in DOMString error);
 };
 
 /*
     attributes here affect the preview, any pictures taken, and/or
     any video recorded by the camera.
 */
-[scriptable, uuid(b8949e5c-55b0-49dd-99a9-68d11342915a)]
+[scriptable, uuid(469e0462-59e4-4ed5-afa9-aecd1256ee30)]
 interface nsICameraControl : nsISupports
 {
     readonly attribute nsICameraCapabilities capabilities;
 
     /* one of the vales chosen from capabilities.effects;
        default is "none" */
     attribute DOMString         effect;
 
@@ -285,25 +292,31 @@ interface nsICameraControl : nsISupports
        if the camera supports it, this may be invoked while the camera is
        already recording video.
 
        invoking this function will stop the preview stream, which must be
        manually restarted (e.g. by calling .play() on it). */
     [implicit_jscontext]
     void takePicture(in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError);
 
-    /* start recording video; 'aOptions' define the frame size of to
-       capture, chosen from capabilities.videoSizes, e.g.:
+    /* get a media stream to be used as a camera viewfinder in video mode; 'aOptions' 
+       define the frame size of the video capture, chosen from capabilities.videoSizes, e.g.:
         {
             width: 640,
-            height: 480
+            height: 480,
+            rotation: 90
         }
     */
     [implicit_jscontext]
-    void startRecording(in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError);
+    void getPreviewStreamVideoMode(in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError);
+
+    /* start recording video; 
+    */
+    [implicit_jscontext]
+    void startRecording(in nsIDOMDeviceStorage storageArea, in DOMString filename, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError);
 
     /* stop precording video. */
     void stopRecording();
 
     /* get a media stream to be used as a camera viewfinder; the options
        define the desired frame size of the preview, chosen from
        capabilities.previewSizes, e.g.:
         {
new file mode 100644
--- /dev/null
+++ b/dom/camera/update.patch
@@ -0,0 +1,2296 @@
+diff --git a/GonkCameraListener.h b/GonkCameraListener.h
+index 67eeef3..243264c 100644
+--- a/GonkCameraListener.h
++++ b/GonkCameraListener.h
+@@ -14,49 +14,16 @@
+  * limitations under the License.
+  */
+ 
+-#ifndef ANDROID_HARDWARE_CAMERA_H
+-#define ANDROID_HARDWARE_CAMERA_H
++#ifndef GONK_CAMERA_LISTENER_H
++#define GONK_CAMERA_LISTENER_H
+ 
+ #include <utils/Timers.h>
+-#include <gui/ISurfaceTexture.h>
+-#include <system/camera.h>
+-#include <camera/ICameraClient.h>
+-#include <camera/ICameraRecordingProxy.h>
+-#include <camera/ICameraRecordingProxyListener.h>
++#include "libcameraservice/CameraHardwareInterface.h"
+ 
+ namespace android {
+ 
+-struct CameraInfo {
+-    /**
+-     * The direction that the camera faces to. It should be CAMERA_FACING_BACK
+-     * or CAMERA_FACING_FRONT.
+-     */
+-    int facing;
+-
+-    /**
+-     * The orientation of the camera image. The value is the angle that the
+-     * camera image needs to be rotated clockwise so it shows correctly on the
+-     * display in its natural orientation. It should be 0, 90, 180, or 270.
+-     *
+-     * For example, suppose a device has a naturally tall screen. The
+-     * back-facing camera sensor is mounted in landscape. You are looking at
+-     * the screen. If the top side of the camera sensor is aligned with the
+-     * right edge of the screen in natural orientation, the value should be
+-     * 90. If the top side of a front-facing camera sensor is aligned with the
+-     * right of the screen, the value should be 270.
+-     */
+-    int orientation;
+-    int mode;
+-};
+-
+-class ICameraService;
+-class ICamera;
+-class Surface;
+-class Mutex;
+-class String8;
+-
+ // ref-counted object for callbacks
+-class CameraListener: virtual public RefBase
++class GonkCameraListener: virtual public RefBase
+ {
+ public:
+     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+@@ -65,133 +32,6 @@ public:
+     virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+ };
+ 
+-class Camera : public BnCameraClient, public IBinder::DeathRecipient
+-{
+-public:
+-            // construct a camera client from an existing remote
+-    static  sp<Camera>  create(const sp<ICamera>& camera);
+-    static  int32_t     getNumberOfCameras();
+-    static  status_t    getCameraInfo(int cameraId,
+-                                      struct CameraInfo* cameraInfo);
+-    static  sp<Camera>  connect(int cameraId);
+-            virtual     ~Camera();
+-            void        init();
+-
+-            status_t    reconnect();
+-            void        disconnect();
+-            status_t    lock();
+-            status_t    unlock();
+-
+-            status_t    getStatus() { return mStatus; }
+-
+-            // pass the buffered Surface to the camera service
+-            status_t    setPreviewDisplay(const sp<Surface>& surface);
+-
+-            // pass the buffered ISurfaceTexture to the camera service
+-            status_t    setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
+-
+-            // start preview mode, must call setPreviewDisplay first
+-            status_t    startPreview();
+-
+-            // stop preview mode
+-            void        stopPreview();
+-
+-            // get preview state
+-            bool        previewEnabled();
+-
+-            // start recording mode, must call setPreviewDisplay first
+-            status_t    startRecording();
+-
+-            // stop recording mode
+-            void        stopRecording();
+-
+-            // get recording state
+-            bool        recordingEnabled();
+-
+-            // release a recording frame
+-            void        releaseRecordingFrame(const sp<IMemory>& mem);
+-
+-            // autoFocus - status returned from callback
+-            status_t    autoFocus();
+-
+-            // cancel auto focus
+-            status_t    cancelAutoFocus();
+-
+-            // take a picture - picture returned from callback
+-            status_t    takePicture(int msgType);
+-
+-            // set preview/capture parameters - key/value pairs
+-            status_t    setParameters(const String8& params);
+-
+-            // get preview/capture parameters - key/value pairs
+-            String8     getParameters() const;
+-
+-            // send command to camera driver
+-            status_t    sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+-
+-            // tell camera hal to store meta data or real YUV in video buffers.
+-            status_t    storeMetaDataInBuffers(bool enabled);
+-
+-            void        setListener(const sp<CameraListener>& listener);
+-            void        setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener);
+-            void        setPreviewCallbackFlags(int preview_callback_flag);
+-
+-            sp<ICameraRecordingProxy> getRecordingProxy();
+-
+-    // ICameraClient interface
+-    virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
+-    virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
+-                                     camera_frame_metadata_t *metadata);
+-    virtual void        dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+-
+-    sp<ICamera>         remote();
+-
+-    class RecordingProxy : public BnCameraRecordingProxy
+-    {
+-    public:
+-        RecordingProxy(const sp<Camera>& camera);
+-
+-        // ICameraRecordingProxy interface
+-        virtual status_t startRecording(const sp<ICameraRecordingProxyListener>& listener);
+-        virtual void stopRecording();
+-        virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+-
+-    private:
+-        sp<Camera>         mCamera;
+-    };
+-
+-private:
+-                        Camera();
+-                        Camera(const Camera&);
+-                        Camera& operator=(const Camera);
+-                        virtual void binderDied(const wp<IBinder>& who);
+-
+-            class DeathNotifier: public IBinder::DeathRecipient
+-            {
+-            public:
+-                DeathNotifier() {
+-                }
+-
+-                virtual void binderDied(const wp<IBinder>& who);
+-            };
+-
+-            static sp<DeathNotifier> mDeathNotifier;
+-
+-            // helper function to obtain camera service handle
+-            static const sp<ICameraService>& getCameraService();
+-
+-            sp<ICamera>         mCamera;
+-            status_t            mStatus;
+-
+-            sp<CameraListener>  mListener;
+-            sp<ICameraRecordingProxyListener>  mRecordingProxyListener;
+-
+-            friend class DeathNotifier;
+-
+-            static  Mutex               mLock;
+-            static  sp<ICameraService>  mCameraService;
+-};
+-
+ }; // namespace android
+ 
+ #endif
+diff --git a/GonkCameraSource.cpp b/GonkCameraSource.cpp
+index af6b340..9dba596 100644
+--- a/GonkCameraSource.cpp
++++ b/GonkCameraSource.cpp
+@@ -14,29 +14,34 @@
+  * limitations under the License.
+  */
+ 
+-//#define LOG_NDEBUG 0
+-#define LOG_TAG "CameraSource"
+-#include <utils/Log.h>
++#include <base/basictypes.h>
++#include "nsDebug.h"
++#define DOM_CAMERA_LOG_LEVEL        3
++#include "CameraCommon.h"
++#define LOGD DOM_CAMERA_LOGA
++#define LOGV DOM_CAMERA_LOGI
++#define LOGI DOM_CAMERA_LOGI
++#define LOGW DOM_CAMERA_LOGW
++#define LOGE DOM_CAMERA_LOGE
+ 
+ #include <OMX_Component.h>
+-#include <binder/IPCThreadState.h>
+-#include <media/stagefright/CameraSource.h>
++#include "GonkCameraSource.h"
++#include "GonkCameraListener.h"
++#include "GonkCameraHwMgr.h"
+ #include <media/stagefright/MediaDebug.h>
+ #include <media/stagefright/MediaDefs.h>
+ #include <media/stagefright/MediaErrors.h>
+ #include <media/stagefright/MetaData.h>
+-#include <camera/Camera.h>
+-#include <camera/CameraParameters.h>
+-#include <surfaceflinger/Surface.h>
+ #include <utils/String8.h>
+ #include <cutils/properties.h>
+ 
++using namespace mozilla;
+ namespace android {
+ 
+ static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
+ 
+-struct CameraSourceListener : public CameraListener {
+-    CameraSourceListener(const sp<CameraSource> &source);
++struct GonkCameraSourceListener : public GonkCameraListener {
++    GonkCameraSourceListener(const sp<GonkCameraSource> &source);
+ 
+     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
+     virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr,
+@@ -46,41 +51,41 @@ struct CameraSourceListener : public CameraListener {
+             nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+ 
+ protected:
+-    virtual ~CameraSourceListener();
++    virtual ~GonkCameraSourceListener();
+ 
+ private:
+-    wp<CameraSource> mSource;
++    wp<GonkCameraSource> mSource;
+ 
+-    CameraSourceListener(const CameraSourceListener &);
+-    CameraSourceListener &operator=(const CameraSourceListener &);
++    GonkCameraSourceListener(const GonkCameraSourceListener &);
++    GonkCameraSourceListener &operator=(const GonkCameraSourceListener &);
+ };
+ 
+-CameraSourceListener::CameraSourceListener(const sp<CameraSource> &source)
++GonkCameraSourceListener::GonkCameraSourceListener(const sp<GonkCameraSource> &source)
+     : mSource(source) {
+ }
+ 
+-CameraSourceListener::~CameraSourceListener() {
++GonkCameraSourceListener::~GonkCameraSourceListener() {
+ }
+ 
+-void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
++void GonkCameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
+     LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
+ }
+ 
+-void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
++void GonkCameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
+                                     camera_frame_metadata_t *metadata) {
+     LOGV("postData(%d, ptr:%p, size:%d)",
+          msgType, dataPtr->pointer(), dataPtr->size());
+ 
+-    sp<CameraSource> source = mSource.promote();
++    sp<GonkCameraSource> source = mSource.promote();
+     if (source.get() != NULL) {
+         source->dataCallback(msgType, dataPtr);
+     }
+ }
+ 
+-void CameraSourceListener::postDataTimestamp(
++void GonkCameraSourceListener::postDataTimestamp(
+         nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
+ 
+-    sp<CameraSource> source = mSource.promote();
++    sp<GonkCameraSource> source = mSource.promote();
+     if (source.get() != NULL) {
+         source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
+     }
+@@ -114,48 +119,30 @@ static int32_t getColorFormat(const char* colorFormat) {
+     }
+ 
+     LOGE("Uknown color format (%s), please add it to "
+-         "CameraSource::getColorFormat", colorFormat);
++         "GonkCameraSource::getColorFormat", colorFormat);
+ 
+     CHECK_EQ(0, "Unknown color format");
+ }
+ 
+-CameraSource *CameraSource::Create() {
+-    Size size;
+-    size.width = -1;
+-    size.height = -1;
+-
+-    sp<ICamera> camera;
+-    return new CameraSource(camera, NULL, 0, size, -1, NULL, false);
+-}
+-
+-// static
+-CameraSource *CameraSource::CreateFromCamera(
+-    const sp<ICamera>& camera,
+-    const sp<ICameraRecordingProxy>& proxy,
+-    int32_t cameraId,
++GonkCameraSource *GonkCameraSource::Create(
++    int32_t cameraHandle,
+     Size videoSize,
+     int32_t frameRate,
+-    const sp<Surface>& surface,
+     bool storeMetaDataInVideoBuffers) {
+ 
+-    CameraSource *source = new CameraSource(camera, proxy, cameraId,
+-                    videoSize, frameRate, surface,
++    GonkCameraSource *source = new GonkCameraSource(cameraHandle,
++                    videoSize, frameRate,
+                     storeMetaDataInVideoBuffers);
+     return source;
+ }
+ 
+-CameraSource::CameraSource(
+-    const sp<ICamera>& camera,
+-    const sp<ICameraRecordingProxy>& proxy,
+-    int32_t cameraId,
++GonkCameraSource::GonkCameraSource(
++    int32_t cameraHandle,
+     Size videoSize,
+     int32_t frameRate,
+-    const sp<Surface>& surface,
+     bool storeMetaDataInVideoBuffers)
+     : mCameraFlags(0),
+       mVideoFrameRate(-1),
+-      mCamera(0),
+-      mSurface(surface),
+       mNumFramesReceived(0),
+       mLastFrameTimestampUs(0),
+       mStarted(false),
+@@ -169,43 +156,19 @@ CameraSource::CameraSource(
+     mVideoSize.width  = -1;
+     mVideoSize.height = -1;
+ 
+-    mInitCheck = init(camera, proxy, cameraId,
++    mCameraHandle = cameraHandle;
++
++    mInitCheck = init(
+                     videoSize, frameRate,
+                     storeMetaDataInVideoBuffers);
+     if (mInitCheck != OK) releaseCamera();
+ }
+ 
+-status_t CameraSource::initCheck() const {
++status_t GonkCameraSource::initCheck() const {
+     return mInitCheck;
+ }
+ 
+-status_t CameraSource::isCameraAvailable(
+-    const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+-    int32_t cameraId) {
+-
+-    if (camera == 0) {
+-        mCamera = Camera::connect(cameraId);
+-        if (mCamera == 0) return -EBUSY;
+-        mCameraFlags &= ~FLAGS_HOT_CAMERA;
+-    } else {
+-        // We get the proxy from Camera, not ICamera. We need to get the proxy
+-        // to the remote Camera owned by the application. Here mCamera is a
+-        // local Camera object created by us. We cannot use the proxy from
+-        // mCamera here.
+-        mCamera = Camera::create(camera);
+-        if (mCamera == 0) return -EBUSY;
+-        mCameraRecordingProxy = proxy;
+-        mCameraFlags |= FLAGS_HOT_CAMERA;
+-        mDeathNotifier = new DeathNotifier();
+-        // isBinderAlive needs linkToDeath to work.
+-        mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
+-    }
+-
+-    mCamera->lock();
+-
+-    return OK;
+-}
+-
++//TODO: Do we need to reimplement isCameraAvailable?
+ 
+ /*
+  * Check to see whether the requested video width and height is one
+@@ -267,7 +230,7 @@ static void getSupportedVideoSizes(
+  * @param params CameraParameters to retrieve the information
+  * @return OK if no error.
+  */
+-status_t CameraSource::isCameraColorFormatSupported(
++status_t GonkCameraSource::isCameraColorFormatSupported(
+         const CameraParameters& params) {
+     mColorFormat = getColorFormat(params.get(
+             CameraParameters::KEY_VIDEO_FRAME_FORMAT));
+@@ -292,7 +255,7 @@ status_t CameraSource::isCameraColorFormatSupported(
+  * @param frameRate the target frame rate in frames per second.
+  * @return OK if no error.
+  */
+-status_t CameraSource::configureCamera(
++status_t GonkCameraSource::configureCamera(
+         CameraParameters* params,
+         int32_t width, int32_t height,
+         int32_t frameRate) {
+@@ -347,10 +310,9 @@ status_t CameraSource::configureCamera(
+ 
+     if (isCameraParamChanged) {
+         // Either frame rate or frame size needs to be changed.
+-        String8 s = params->flatten();
+-        if (OK != mCamera->setParameters(s)) {
++        if (OK != GonkCameraHardware::PushParameters(mCameraHandle,*params)) {
+             LOGE("Could not change settings."
+-                 " Someone else is using camera %p?", mCamera.get());
++                 " Someone else is using camera ?");
+             return -EBUSY;
+         }
+     }
+@@ -368,7 +330,7 @@ status_t CameraSource::configureCamera(
+  * @param the target video frame height in pixels to check against
+  * @return OK if no error
+  */
+-status_t CameraSource::checkVideoSize(
++status_t GonkCameraSource::checkVideoSize(
+         const CameraParameters& params,
+         int32_t width, int32_t height) {
+ 
+@@ -420,7 +382,7 @@ status_t CameraSource::checkVideoSize(
+  * @param the target video frame rate to check against
+  * @return OK if no error.
+  */
+-status_t CameraSource::checkFrameRate(
++status_t GonkCameraSource::checkFrameRate(
+         const CameraParameters& params,
+         int32_t frameRate) {
+ 
+@@ -462,39 +424,17 @@ status_t CameraSource::checkFrameRate(
+  *
+  * @return OK if no error.
+  */
+-status_t CameraSource::init(
+-        const sp<ICamera>& camera,
+-        const sp<ICameraRecordingProxy>& proxy,
+-        int32_t cameraId,
++status_t GonkCameraSource::init(
+         Size videoSize,
+         int32_t frameRate,
+         bool storeMetaDataInVideoBuffers) {
+ 
+     LOGV("init");
+     status_t err = OK;
+-    int64_t token = IPCThreadState::self()->clearCallingIdentity();
+-    err = initWithCameraAccess(camera, proxy, cameraId,
+-                               videoSize, frameRate,
+-                               storeMetaDataInVideoBuffers);
+-    IPCThreadState::self()->restoreCallingIdentity(token);
+-    return err;
+-}
+-
+-status_t CameraSource::initWithCameraAccess(
+-        const sp<ICamera>& camera,
+-        const sp<ICameraRecordingProxy>& proxy,
+-        int32_t cameraId,
+-        Size videoSize,
+-        int32_t frameRate,
+-        bool storeMetaDataInVideoBuffers) {
+-    LOGV("initWithCameraAccess");
+-    status_t err = OK;
++    //TODO: need to do something here to check the sanity of camera
+ 
+-    if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
+-        LOGE("Camera connection could not be established.");
+-        return err;
+-    }
+-    CameraParameters params(mCamera->getParameters());
++    CameraParameters params;
++    GonkCameraHardware::PullParameters(mCameraHandle, params);
+     if ((err = isCameraColorFormatSupported(params)) != OK) {
+         return err;
+     }
+@@ -508,7 +448,8 @@ status_t CameraSource::initWithCameraAccess(
+     }
+ 
+     // Check on video frame size and frame rate.
+-    CameraParameters newCameraParams(mCamera->getParameters());
++    CameraParameters newCameraParams;
++    GonkCameraHardware::PullParameters(mCameraHandle, newCameraParams);
+     if ((err = checkVideoSize(newCameraParams,
+                 videoSize.width, videoSize.height)) != OK) {
+         return err;
+@@ -517,15 +458,11 @@ status_t CameraSource::initWithCameraAccess(
+         return err;
+     }
+ 
+-    // This CHECK is good, since we just passed the lock/unlock
+-    // check earlier by calling mCamera->setParameters().
+-    CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface));
+-
+     // By default, do not store metadata in video buffers
+     mIsMetaDataStoredInVideoBuffers = false;
+-    mCamera->storeMetaDataInBuffers(false);
++    GonkCameraHardware::StoreMetaDataInBuffers(mCameraHandle, false);
+     if (storeMetaDataInVideoBuffers) {
+-        if (OK == mCamera->storeMetaDataInBuffers(true)) {
++        if (OK == GonkCameraHardware::StoreMetaDataInBuffers(mCameraHandle, true)) {
+             mIsMetaDataStoredInVideoBuffers = true;
+         }
+     }
+@@ -568,40 +505,28 @@ status_t CameraSource::initWithCameraAccess(
+     return OK;
+ }
+ 
+-CameraSource::~CameraSource() {
++GonkCameraSource::~GonkCameraSource() {
+     if (mStarted) {
+         stop();
+     } else if (mInitCheck == OK) {
+         // Camera is initialized but because start() is never called,
+         // the lock on Camera is never released(). This makes sure
+         // Camera's lock is released in this case.
++        // TODO: Don't think I need to do this
+         releaseCamera();
+     }
+ }
+ 
+-void CameraSource::startCameraRecording() {
++void GonkCameraSource::startCameraRecording() {
+     LOGV("startCameraRecording");
+-    // Reset the identity to the current thread because media server owns the
+-    // camera and recording is started by the applications. The applications
+-    // will connect to the camera in ICameraRecordingProxy::startRecording.
+-    int64_t token = IPCThreadState::self()->clearCallingIdentity();
+-    if (mCameraFlags & FLAGS_HOT_CAMERA) {
+-        mCamera->unlock();
+-        mCamera.clear();
+-        CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+-    } else {
+-        mCamera->setListener(new CameraSourceListener(this));
+-        mCamera->startRecording();
+-        CHECK(mCamera->recordingEnabled());
+-    }
+-    IPCThreadState::self()->restoreCallingIdentity(token);
++    CHECK_EQ(OK, GonkCameraHardware::StartRecording(mCameraHandle));
+ }
+ 
+-status_t CameraSource::start(MetaData *meta) {
++status_t GonkCameraSource::start(MetaData *meta) {
+     LOGV("start");
+     CHECK(!mStarted);
+     if (mInitCheck != OK) {
+-        LOGE("CameraSource is not initialized yet");
++        LOGE("GonkCameraSource is not initialized yet");
+         return mInitCheck;
+     }
+ 
+@@ -614,58 +539,34 @@ status_t CameraSource::start(MetaData *meta) {
+     mStartTimeUs = 0;
+     int64_t startTimeUs;
+     if (meta && meta->findInt64(kKeyTime, &startTimeUs)) {
++        LOGV("Metadata enabled, startime: %lld us", startTimeUs);
+         mStartTimeUs = startTimeUs;
+     }
+ 
++    // Register a listener with GonkCameraHardware so that we can get callbacks
++    GonkCameraHardware::SetListener(mCameraHandle, new GonkCameraSourceListener(this));
++
+     startCameraRecording();
+ 
+     mStarted = true;
+     return OK;
+ }
+ 
+-void CameraSource::stopCameraRecording() {
++void GonkCameraSource::stopCameraRecording() {
+     LOGV("stopCameraRecording");
+-    if (mCameraFlags & FLAGS_HOT_CAMERA) {
+-        mCameraRecordingProxy->stopRecording();
+-    } else {
+-        mCamera->setListener(NULL);
+-        mCamera->stopRecording();
+-    }
++    GonkCameraHardware::StopRecording(mCameraHandle);
+ }
+ 
+-void CameraSource::releaseCamera() {
++void GonkCameraSource::releaseCamera() {
+     LOGV("releaseCamera");
+-    if (mCamera != 0) {
+-        int64_t token = IPCThreadState::self()->clearCallingIdentity();
+-        if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
+-            LOGV("Camera was cold when we started, stopping preview");
+-            mCamera->stopPreview();
+-            mCamera->disconnect();
+-        }
+-        mCamera->unlock();
+-        mCamera.clear();
+-        mCamera = 0;
+-        IPCThreadState::self()->restoreCallingIdentity(token);
+-    }
+-    if (mCameraRecordingProxy != 0) {
+-        mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
+-        mCameraRecordingProxy.clear();
+-    }
+-    mCameraFlags = 0;
+ }
+ 
+-status_t CameraSource::stop() {
+-    LOGD("stop: E");
++status_t GonkCameraSource::stop() {
++    LOGV("stop: E");
+     Mutex::Autolock autoLock(mLock);
+     mStarted = false;
+     mFrameAvailableCondition.signal();
+ 
+-    int64_t token;
+-    bool isTokenValid = false;
+-    if (mCamera != 0) {
+-        token = IPCThreadState::self()->clearCallingIdentity();
+-        isTokenValid = true;
+-    }
+     releaseQueuedFrames();
+     while (!mFramesBeingEncoded.empty()) {
+         if (NO_ERROR !=
+@@ -675,11 +576,9 @@ status_t CameraSource::stop() {
+                 mFramesBeingEncoded.size());
+         }
+     }
++    LOGV("Calling stopCameraRecording");
+     stopCameraRecording();
+     releaseCamera();
+-    if (isTokenValid) {
+-        IPCThreadState::self()->restoreCallingIdentity(token);
+-    }
+ 
+     if (mCollectStats) {
+         LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
+@@ -692,22 +591,16 @@ status_t CameraSource::stop() {
+     }
+ 
+     CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
+-    LOGD("stop: X");
++    LOGV("stop: X");
+     return OK;
+ }
+ 
+-void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
++void GonkCameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
+     LOGV("releaseRecordingFrame");
+-    if (mCameraRecordingProxy != NULL) {
+-        mCameraRecordingProxy->releaseRecordingFrame(frame);
+-    } else if (mCamera != NULL) {
+-        int64_t token = IPCThreadState::self()->clearCallingIdentity();
+-        mCamera->releaseRecordingFrame(frame);
+-        IPCThreadState::self()->restoreCallingIdentity(token);
+-    }
++    GonkCameraHardware::ReleaseRecordingFrame(mCameraHandle, frame);
+ }
+ 
+-void CameraSource::releaseQueuedFrames() {
++void GonkCameraSource::releaseQueuedFrames() {
+     List<sp<IMemory> >::iterator it;
+     while (!mFramesReceived.empty()) {
+         it = mFramesReceived.begin();
+@@ -717,15 +610,15 @@ void CameraSource::releaseQueuedFrames() {
+     }
+ }
+ 
+-sp<MetaData> CameraSource::getFormat() {
++sp<MetaData> GonkCameraSource::getFormat() {
+     return mMeta;
+ }
+ 
+-void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
++void GonkCameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
+     releaseRecordingFrame(frame);
+ }
+ 
+-void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
++void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) {
+     LOGV("signalBufferReturned: %p", buffer->data());
+     Mutex::Autolock autoLock(mLock);
+     for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
+@@ -743,7 +636,7 @@ void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
+     CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+ }
+ 
+-status_t CameraSource::read(
++status_t GonkCameraSource::read(
+         MediaBuffer **buffer, const ReadOptions *options) {
+     LOGV("read");
+ 
+@@ -764,11 +657,7 @@ status_t CameraSource::read(
+             if (NO_ERROR !=
+                 mFrameAvailableCondition.waitRelative(mLock,
+                     mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
+-                if (mCameraRecordingProxy != 0 &&
+-                    !mCameraRecordingProxy->asBinder()->isBinderAlive()) {
+-                    LOGW("camera recording proxy is gone");
+-                    return ERROR_END_OF_STREAM;
+-                }
++                //TODO: check sanity of camera?
+                 LOGW("Timed out waiting for incoming camera video frames: %lld us",
+                     mLastFrameTimestampUs);
+             }
+@@ -790,9 +679,10 @@ status_t CameraSource::read(
+     return OK;
+ }
+ 
+-void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
++void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
+         int32_t msgType, const sp<IMemory> &data) {
+     LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
++    //LOGV("dataCallbackTimestamp: data %x size %d", data->pointer(), data->size());
+     Mutex::Autolock autoLock(mLock);
+     if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
+         LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
+@@ -808,7 +698,7 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
+     }
+ 
+     // May need to skip frame or modify timestamp. Currently implemented
+-    // by the subclass CameraSourceTimeLapse.
++    // by the subclass GonkCameraSourceTimeLapse.
+     if (skipCurrentFrame(timestampUs)) {
+         releaseOneRecordingFrame(data);
+         return;
+@@ -839,22 +729,9 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
+     mFrameAvailableCondition.signal();
+ }
+ 
+-bool CameraSource::isMetaDataStoredInVideoBuffers() const {
++bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {
+     LOGV("isMetaDataStoredInVideoBuffers");
+     return mIsMetaDataStoredInVideoBuffers;
+ }
+ 
+-CameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
+-    mSource = source;
+-}
+-
+-void CameraSource::ProxyListener::dataCallbackTimestamp(
+-        nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
+-    mSource->dataCallbackTimestamp(timestamp / 1000, msgType, dataPtr);
+-}
+-
+-void CameraSource::DeathNotifier::binderDied(const wp<IBinder>& who) {
+-    LOGI("Camera recording proxy died");
+-}
+-
+-}  // namespace android
++} // namespace android
+diff --git a/GonkCameraSource.h b/GonkCameraSource.h
+index 446720b..fe58f96 100644
+--- a/GonkCameraSource.h
++++ b/GonkCameraSource.h
+@@ -14,69 +14,31 @@
+  * limitations under the License.
+  */
+ 
+-#ifndef CAMERA_SOURCE_H_
++#ifndef GONK_CAMERA_SOURCE_H_
+ 
+-#define CAMERA_SOURCE_H_
++#define GONK_CAMERA_SOURCE_H_
+ 
+ #include <media/stagefright/MediaBuffer.h>
+ #include <media/stagefright/MediaSource.h>
+-#include <camera/ICamera.h>
+-#include <camera/ICameraRecordingProxyListener.h>
+ #include <camera/CameraParameters.h>
+ #include <utils/List.h>
+ #include <utils/RefBase.h>
++#include <utils/threads.h>
+ 
+ namespace android {
+ 
+ class IMemory;
+-class Camera;
+-class Surface;
++class GonkCameraSourceListener;
+ 
+-class CameraSource : public MediaSource, public MediaBufferObserver {
++class GonkCameraSource : public MediaSource, public MediaBufferObserver {
+ public:
+-    /**
+-     * Factory method to create a new CameraSource using the current
+-     * settings (such as video size, frame rate, color format, etc)
+-     * from the default camera.
+-     *
+-     * @return NULL on error.
+-     */
+-    static CameraSource *Create();
+ 
+-    /**
+-     * Factory method to create a new CameraSource.
+-     *
+-     * @param camera the video input frame data source. If it is NULL,
+-     *          we will try to connect to the camera with the given
+-     *          cameraId.
+-     *
+-     * @param cameraId the id of the camera that the source will connect
+-     *          to if camera is NULL; otherwise ignored.
+-     *
+-     * @param videoSize the dimension (in pixels) of the video frame
+-     * @param frameRate the target frames per second
+-     * @param surface the preview surface for display where preview
+-     *          frames are sent to
+-     * @param storeMetaDataInVideoBuffers true to request the camera
+-     *          source to store meta data in video buffers; false to
+-     *          request the camera source to store real YUV frame data
+-     *          in the video buffers. The camera source may not support
+-     *          storing meta data in video buffers, if so, a request
+-     *          to do that will NOT be honored. To find out whether
+-     *          meta data is actually being stored in video buffers
+-     *          during recording, call isMetaDataStoredInVideoBuffers().
+-     *
+-     * @return NULL on error.
+-     */
+-    static CameraSource *CreateFromCamera(const sp<ICamera> &camera,
+-                                          const sp<ICameraRecordingProxy> &proxy,
+-                                          int32_t cameraId,
+-                                          Size videoSize,
+-                                          int32_t frameRate,
+-                                          const sp<Surface>& surface,
+-                                          bool storeMetaDataInVideoBuffers = false);
++    static GonkCameraSource *Create(int32_t cameraHandle,
++                                    Size videoSize,
++                                    int32_t frameRate,
++                                    bool storeMetaDataInVideoBuffers = false);
+ 
+-    virtual ~CameraSource();
++    virtual ~GonkCameraSource();
+ 
+     virtual status_t start(MetaData *params = NULL);
+     virtual status_t stop();
+@@ -84,14 +46,14 @@ public:
+             MediaBuffer **buffer, const ReadOptions *options = NULL);
+ 
+     /**
+-     * Check whether a CameraSource object is properly initialized.
++     * Check whether a GonkCameraSource object is properly initialized.
+      * Must call this method before stop().
+      * @return OK if initialization has successfully completed.
+      */
+     virtual status_t initCheck() const;
+ 
+     /**
+-     * Returns the MetaData associated with the CameraSource,
++     * Returns the MetaData associated with the GonkCameraSource,
+      * including:
+      * kKeyColorFormat: YUV color format of the video frames
+      * kKeyWidth, kKeyHeight: dimension (in pixels) of the video frames
+@@ -113,22 +75,6 @@ public:
+     virtual void signalBufferReturned(MediaBuffer* buffer);
+ 
+ protected:
+-    class ProxyListener: public BnCameraRecordingProxyListener {
+-    public:
+-        ProxyListener(const sp<CameraSource>& source);
+-        virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
+-                const sp<IMemory> &data);
+-
+-    private:
+-        sp<CameraSource> mSource;
+-    };
+-
+-    // isBinderAlive needs linkToDeath to work.
+-    class DeathNotifier: public IBinder::DeathRecipient {
+-    public:
+-        DeathNotifier() {}
+-        virtual void binderDied(const wp<IBinder>& who);
+-    };
+ 
+     enum CameraFlags {
+         FLAGS_SET_CAMERA = 1L << 0,
+@@ -141,10 +87,6 @@ protected:
+     int32_t  mColorFormat;
+     status_t mInitCheck;
+ 
+-    sp<Camera>   mCamera;
+-    sp<ICameraRecordingProxy>   mCameraRecordingProxy;
+-    sp<DeathNotifier> mDeathNotifier;
+-    sp<Surface>  mSurface;
+     sp<MetaData> mMeta;
+ 
+     int64_t mStartTimeUs;
+@@ -156,11 +98,9 @@ protected:
+     // Time between capture of two frames.
+     int64_t mTimeBetweenFrameCaptureUs;
+ 
+-    CameraSource(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+-                 int32_t cameraId,
++    GonkCameraSource(int32_t cameraHandle,
+                  Size videoSize, int32_t frameRate,
+-                 const sp<Surface>& surface,
+-                 bool storeMetaDataInVideoBuffers);
++                 bool storeMetaDataInVideoBuffers = false);
+ 
+     virtual void startCameraRecording();
+     virtual void stopCameraRecording();
+@@ -170,6 +110,7 @@ protected:
+     // Called from dataCallbackTimestamp.
+     virtual bool skipCurrentFrame(int64_t timestampUs) {return false;}
+ 
++    friend class GonkCameraSourceListener;
+     // Callback called when still camera raw data is available.
+     virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {}
+ 
+@@ -177,7 +118,6 @@ protected:
+             const sp<IMemory> &data);
+ 
+ private:
+-    friend class CameraSourceListener;
+ 
+     Mutex mLock;
+     Condition mFrameAvailableCondition;
+@@ -192,23 +132,13 @@ private:
+     int64_t mGlitchDurationThresholdUs;
+     bool mCollectStats;
+     bool mIsMetaDataStoredInVideoBuffers;
++    int32_t mCameraHandle;
+ 
+     void releaseQueuedFrames();
+     void releaseOneRecordingFrame(const sp<IMemory>& frame);
+ 
+-
+-    status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+-                  int32_t cameraId, Size videoSize, int32_t frameRate,
+-                  bool storeMetaDataInVideoBuffers);
+-
+-    status_t initWithCameraAccess(
+-                  const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+-                  int32_t cameraId, Size videoSize, int32_t frameRate,
++    status_t init(Size videoSize, int32_t frameRate,
+                   bool storeMetaDataInVideoBuffers);
+-
+-    status_t isCameraAvailable(const sp<ICamera>& camera,
+-                               const sp<ICameraRecordingProxy>& proxy,
+-                               int32_t cameraId);
+     status_t isCameraColorFormatSupported(const CameraParameters& params);
+     status_t configureCamera(CameraParameters* params,
+                     int32_t width, int32_t height,
+@@ -222,10 +152,10 @@ private:
+ 
+     void releaseCamera();
+ 
+-    CameraSource(const CameraSource &);
+-    CameraSource &operator=(const CameraSource &);
++    GonkCameraSource(const GonkCameraSource &);
++    GonkCameraSource &operator=(const GonkCameraSource &);
+ };
+ 
+ }  // namespace android
+ 
+-#endif  // CAMERA_SOURCE_H_
++#endif  // GONK_CAMERA_SOURCE_H_
+diff --git a/GonkRecorder.cpp b/GonkRecorder.cpp
+index b20ca9d..2dc625c 100644
+--- a/GonkRecorder.cpp
++++ b/GonkRecorder.cpp
+@@ -16,35 +16,23 @@
+  */
+ 
+ //#define LOG_NDEBUG 0
+-#define LOG_TAG "StagefrightRecorder"
++#define LOG_TAG "GonkRecorder"
++
+ #include <utils/Log.h>
+ #include <media/AudioParameter.h>
+-#include "StagefrightRecorder.h"
+-
+-#include <binder/IPCThreadState.h>
+-#include <binder/IServiceManager.h>
++#include "GonkRecorder.h"
+ 
+-#include <media/IMediaPlayerService.h>
+ #include <media/stagefright/AudioSource.h>
+ #include <media/stagefright/AMRWriter.h>
+-#include <media/stagefright/AACWriter.h>
+-#include <media/stagefright/ExtendedWriter.h>
+-#include <media/stagefright/FMA2DPWriter.h>
+-#include <media/stagefright/CameraSource.h>
+-#include <media/stagefright/CameraSourceTimeLapse.h>
+ #include <media/stagefright/ExtendedWriter.h>
+ #include <media/stagefright/MPEG2TSWriter.h>
+ #include <media/stagefright/MPEG4Writer.h>
+ #include <media/stagefright/MediaDebug.h>
+ #include <media/stagefright/MediaDefs.h>
+ #include <media/stagefright/MetaData.h>
+-#include <media/stagefright/OMXClient.h>
++#include <OMX.h>
+ #include <media/stagefright/OMXCodec.h>
+-#include <media/stagefright/SurfaceMediaSource.h>
+ #include <media/MediaProfiles.h>
+-#include <camera/ICamera.h>
+-#include <camera/CameraParameters.h>
+-#include <surfaceflinger/Surface.h>
+ #include <utils/String8.h>
+ 
+ #include <utils/Errors.h>
+@@ -57,51 +45,41 @@
+ #include "ARTPWriter.h"
+ 
+ #include <cutils/properties.h>
++#include "GonkCameraSource.h"
+ 
+ namespace android {
+ 
+-// To collect the encoder usage for the battery app
+-static void addBatteryData(uint32_t params) {
+-    sp<IBinder> binder =
+-        defaultServiceManager()->getService(String16("media.player"));
+-    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+-    CHECK(service.get() != NULL);
+-
+-    service->addBatteryData(params);
++static sp<IOMX> sOMX = NULL;
++static sp<IOMX> GetOMX() {
++  if(sOMX.get() == NULL) {
++    sOMX = new OMX;
++    }
++  return sOMX;
+ }
+ 
+-
+-StagefrightRecorder::StagefrightRecorder()
++GonkRecorder::GonkRecorder()
+     : mWriter(NULL),
+       mOutputFd(-1),
+       mAudioSource(AUDIO_SOURCE_CNT),
+       mVideoSource(VIDEO_SOURCE_LIST_END),
+-      mStarted(false), mSurfaceMediaSource(NULL),
++      mStarted(false),
+       mDisableAudio(false) {
+ 
+     LOGV("Constructor");
+     reset();
+ }
+ 
+-StagefrightRecorder::~StagefrightRecorder() {
++GonkRecorder::~GonkRecorder() {
+     LOGV("Destructor");
+     stop();
+ }
+ 
+-status_t StagefrightRecorder::init() {
++status_t GonkRecorder::init() {
+     LOGV("init");
+     return OK;
+ }
+ 
+-// The client side of mediaserver asks it to creat a SurfaceMediaSource
+-// and return a interface reference. The client side will use that
+-// while encoding GL Frames
+-sp<ISurfaceTexture> StagefrightRecorder::querySurfaceMediaSource() const {
+-    LOGV("Get SurfaceMediaSource");
+-    return mSurfaceMediaSource;
+-}
+-
+-status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
++status_t GonkRecorder::setAudioSource(audio_source_t as) {
+     LOGV("setAudioSource: %d", as);
+     if (as < AUDIO_SOURCE_DEFAULT ||
+         as >= AUDIO_SOURCE_CNT) {
+@@ -122,7 +100,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setVideoSource(video_source vs) {
++status_t GonkRecorder::setVideoSource(video_source vs) {
+     LOGV("setVideoSource: %d", vs);
+     if (vs < VIDEO_SOURCE_DEFAULT ||
+         vs >= VIDEO_SOURCE_LIST_END) {
+@@ -139,7 +117,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setOutputFormat(output_format of) {
++status_t GonkRecorder::setOutputFormat(output_format of) {
+     LOGV("setOutputFormat: %d", of);
+     if (of < OUTPUT_FORMAT_DEFAULT ||
+         of >= OUTPUT_FORMAT_LIST_END) {
+@@ -156,7 +134,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
++status_t GonkRecorder::setAudioEncoder(audio_encoder ae) {
+     LOGV("setAudioEncoder: %d", ae);
+     if (ae < AUDIO_ENCODER_DEFAULT ||
+         ae >= AUDIO_ENCODER_LIST_END) {
+@@ -174,21 +152,10 @@
+         mAudioEncoder = ae;
+     }
+ 
+-    // Use default values if appropriate setparam's weren't called.
+-    if(mAudioEncoder == AUDIO_ENCODER_AAC) {
+-        mSampleRate = mSampleRate ? mSampleRate : 48000;
+-        mAudioChannels = mAudioChannels ? mAudioChannels : 2;
+-        mAudioBitRate = mAudioBitRate ? mAudioBitRate : 156000;
+-    }
+-    else{
+-        mSampleRate = mSampleRate ? mSampleRate : 8000;
+-        mAudioChannels = mAudioChannels ? mAudioChannels : 1;
+-        mAudioBitRate = mAudioBitRate ? mAudioBitRate : 12200;
+-    }
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
++status_t GonkRecorder::setVideoEncoder(video_encoder ve) {
+     LOGV("setVideoEncoder: %d", ve);
+     if (ve < VIDEO_ENCODER_DEFAULT ||
+         ve >= VIDEO_ENCODER_LIST_END) {
+@@ -205,7 +172,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setVideoSize(int width, int height) {
++status_t GonkRecorder::setVideoSize(int width, int height) {
+     LOGV("setVideoSize: %dx%d", width, height);
+     if (width <= 0 || height <= 0) {
+         LOGE("Invalid video size: %dx%d", width, height);
+@@ -219,7 +186,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
++status_t GonkRecorder::setVideoFrameRate(int frames_per_second) {
+     LOGV("setVideoFrameRate: %d", frames_per_second);
+     if ((frames_per_second <= 0 && frames_per_second != -1) ||
+         frames_per_second > 120) {
+@@ -233,31 +200,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera,
+-                                        const sp<ICameraRecordingProxy> &proxy) {
+-    LOGV("setCamera");
+-    if (camera == 0) {
+-        LOGE("camera is NULL");
+-        return BAD_VALUE;
+-    }
+-    if (proxy == 0) {
+-        LOGE("camera proxy is NULL");
+-        return BAD_VALUE;
+-    }
+-
+-    mCamera = camera;
+-    mCameraProxy = proxy;
+-    return OK;
+-}
+-
+-status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
+-    LOGV("setPreviewSurface: %p", surface.get());
+-    mPreviewSurface = surface;
+-
+-    return OK;
+-}
+-
+-status_t StagefrightRecorder::setOutputFile(const char *path) {
++status_t GonkRecorder::setOutputFile(const char *path) {
+     LOGE("setOutputFile(const char*) must not be called");
+     // We don't actually support this at all, as the media_server process
+     // no longer has permissions to create files.
+@@ -265,7 +208,7 @@
+     return -EPERM;
+ }
+ 
+-status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
++status_t GonkRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
+     LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
+     // These don't make any sense, do they?
+     CHECK_EQ(offset, 0);
+@@ -339,7 +282,7 @@
+     s->setTo(String8(&data[leading_space], i - leading_space));
+ }
+ 
+-status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
++status_t GonkRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
+     LOGV("setParamAudioSamplingRate: %d", sampleRate);
+     if (sampleRate <= 0) {
+         LOGE("Invalid audio sampling rate: %d", sampleRate);
+@@ -351,7 +294,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
++status_t GonkRecorder::setParamAudioNumberOfChannels(int32_t channels) {
+     LOGV("setParamAudioNumberOfChannels: %d", channels);
+     if (channels <= 0 || channels >= 3) {
+         LOGE("Invalid number of audio channels: %d", channels);
+@@ -363,7 +306,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
++status_t GonkRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
+     LOGV("setParamAudioEncodingBitRate: %d", bitRate);
+     if (bitRate <= 0) {
+         LOGE("Invalid audio encoding bit rate: %d", bitRate);
+@@ -378,7 +321,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
++status_t GonkRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
+     LOGV("setParamVideoEncodingBitRate: %d", bitRate);
+     if (bitRate <= 0) {
+         LOGE("Invalid video encoding bit rate: %d", bitRate);
+@@ -394,7 +337,7 @@
+ }
+ 
+ // Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
+-status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
++status_t GonkRecorder::setParamVideoRotation(int32_t degrees) {
+     LOGV("setParamVideoRotation: %d", degrees);
+     if (degrees < 0 || degrees % 90 != 0) {
+         LOGE("Unsupported video rotation angle: %d", degrees);
+@@ -404,7 +347,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
++status_t GonkRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
+     LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
+ 
+     // This is meant for backward compatibility for MediaRecorder.java
+@@ -423,7 +366,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
++status_t GonkRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
+     LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
+ 
+     // This is meant for backward compatibility for MediaRecorder.java
+@@ -449,7 +392,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
++status_t GonkRecorder::setParamInterleaveDuration(int32_t durationUs) {
+     LOGV("setParamInterleaveDuration: %d", durationUs);
+     if (durationUs <= 500000) {           //  500 ms
+         // If interleave duration is too small, it is very inefficient to do
+@@ -471,20 +414,20 @@
+ // If seconds <  0, only the first frame is I frame, and rest are all P frames
+ // If seconds == 0, all frames are encoded as I frames. No P frames
+ // If seconds >  0, it is the time spacing (seconds) between 2 neighboring I frames
+-status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
++status_t GonkRecorder::setParamVideoIFramesInterval(int32_t seconds) {
+     LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
+     mIFramesIntervalSec = seconds;
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
++status_t GonkRecorder::setParam64BitFileOffset(bool use64Bit) {
+     LOGV("setParam64BitFileOffset: %s",
+         use64Bit? "use 64 bit file offset": "use 32 bit file offset");
+     mUse64BitFileOffset = use64Bit;
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
++status_t GonkRecorder::setParamVideoCameraId(int32_t cameraId) {
+     LOGV("setParamVideoCameraId: %d", cameraId);
+     if (cameraId < 0) {
+         return BAD_VALUE;
+@@ -493,7 +436,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
++status_t GonkRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
+     LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
+     if (timeDurationUs < 20000) {  // Infeasible if shorter than 20 ms?
+         LOGE("Tracking time duration too short: %lld us", timeDurationUs);
+@@ -503,7 +446,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
++status_t GonkRecorder::setParamVideoEncoderProfile(int32_t profile) {
+     LOGV("setParamVideoEncoderProfile: %d", profile);
+ 
+     // Additional check will be done later when we load the encoder.
+@@ -512,7 +455,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
++status_t GonkRecorder::setParamVideoEncoderLevel(int32_t level) {
+     LOGV("setParamVideoEncoderLevel: %d", level);
+ 
+     // Additional check will be done later when we load the encoder.
+@@ -521,7 +464,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
++status_t GonkRecorder::setParamMovieTimeScale(int32_t timeScale) {
+     LOGV("setParamMovieTimeScale: %d", timeScale);
+ 
+     // The range is set to be the same as the audio's time scale range
+@@ -534,7 +477,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
++status_t GonkRecorder::setParamVideoTimeScale(int32_t timeScale) {
+     LOGV("setParamVideoTimeScale: %d", timeScale);
+ 
+     // 60000 is chosen to make sure that each video frame from a 60-fps
+@@ -547,7 +490,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
++status_t GonkRecorder::setParamAudioTimeScale(int32_t timeScale) {
+     LOGV("setParamAudioTimeScale: %d", timeScale);
+ 
+     // 96000 Hz is the highest sampling rate support in AAC.
+@@ -559,33 +502,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
+-    LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
+-
+-    if(timeLapseEnable == 0) {
+-        mCaptureTimeLapse = false;
+-    } else if (timeLapseEnable == 1) {
+-        mCaptureTimeLapse = true;
+-    } else {
+-        return BAD_VALUE;
+-    }
+-    return OK;
+-}
+-
+-status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
+-    LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
+-
+-    // Not allowing time more than a day
+-    if (timeUs <= 0 || timeUs > 86400*1E6) {
+-        LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
+-        return BAD_VALUE;
+-    }
+-
+-    mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
+-    return OK;
+-}
+-
+-status_t StagefrightRecorder::setParamGeoDataLongitude(
++status_t GonkRecorder::setParamGeoDataLongitude(
+     int64_t longitudex10000) {
+ 
+     if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
+@@ -595,7 +512,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParamGeoDataLatitude(
++status_t GonkRecorder::setParamGeoDataLatitude(
+     int64_t latitudex10000) {
+ 
+     if (latitudex10000 > 900000 || latitudex10000 < -900000) {
+@@ -605,7 +522,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setParameter(
++status_t GonkRecorder::setParameter(
+         const String8 &key, const String8 &value) {
+     LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
+     if (key == "max-duration") {
+@@ -703,24 +620,13 @@
+         if (safe_strtoi32(value.string(), &timeScale)) {
+             return setParamVideoTimeScale(timeScale);
+         }
+-    } else if (key == "time-lapse-enable") {
+-        int32_t timeLapseEnable;
+-        if (safe_strtoi32(value.string(), &timeLapseEnable)) {
+-            return setParamTimeLapseEnable(timeLapseEnable);
+-        }
+-    } else if (key == "time-between-time-lapse-frame-capture") {
+-        int64_t timeBetweenTimeLapseFrameCaptureMs;
+-        if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
+-            return setParamTimeBetweenTimeLapseFrameCapture(
+-                    1000LL * timeBetweenTimeLapseFrameCaptureMs);
+-        }
+     } else {
+         LOGE("setParameter: failed to find key %s", key.string());
+     }
+     return BAD_VALUE;
+ }
+ 
+-status_t StagefrightRecorder::setParameters(const String8 &params) {
++status_t GonkRecorder::setParameters(const String8 &params) {
+     LOGV("setParameters: %s", params.string());
+     const char *cparams = params.string();
+     const char *key_start = cparams;
+@@ -755,13 +661,13 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
++status_t GonkRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
+     mListener = listener;
+ 
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::prepare() {
++status_t GonkRecorder::prepare() {
+   LOGV(" %s E", __func__ );
+ 
+   if(mVideoSource != VIDEO_SOURCE_LIST_END && mVideoEncoder != VIDEO_ENCODER_LIST_END && mVideoHeight && mVideoWidth &&             /*Video recording*/
+@@ -776,17 +682,15 @@
+   return OK;
+ }
+ 
+-status_t StagefrightRecorder::start() {
++status_t GonkRecorder::start() {
+     CHECK(mOutputFd >= 0);
+ 
+     if (mWriter != NULL) {
+-        LOGE("File writer is not avaialble");
++        LOGE("File writer is not available");
+         return UNKNOWN_ERROR;
+     }
+ 
+     status_t status = OK;
+-    if(AUDIO_SOURCE_FM_RX_A2DP == mAudioSource)
+-        return startFMA2DPWriter();
+ 
+     switch (mOutputFormat) {
+         case OUTPUT_FORMAT_DEFAULT:
+@@ -800,22 +704,9 @@
+             status = startAMRRecording();
+             break;
+ 
+-        case OUTPUT_FORMAT_AAC_ADIF:
+-        case OUTPUT_FORMAT_AAC_ADTS:
+-            status = startAACRecording();
+-            break;
+-
+-        case OUTPUT_FORMAT_RTP_AVP:
+-            status = startRTPRecording();
+-            break;
+-
+         case OUTPUT_FORMAT_MPEG2TS:
+             status = startMPEG2TSRecording();
+ 		    break;
+-			
+-        case OUTPUT_FORMAT_QCP:
+-            status = startExtendedRecording( );
+-		    break;
+         default:
+             LOGE("Unsupported output file format: %d", mOutputFormat);
+             status = UNKNOWN_ERROR;
+@@ -824,22 +715,12 @@
+ 
+     if ((status == OK) && (!mStarted)) {
+         mStarted = true;
+-
+-        uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
+-        if (mAudioSource != AUDIO_SOURCE_CNT) {
+-            params |= IMediaPlayerService::kBatteryDataTrackAudio;
+-        }
+-        if (mVideoSource != VIDEO_SOURCE_LIST_END) {
+-            params |= IMediaPlayerService::kBatteryDataTrackVideo;
+-        }
+-
+-        addBatteryData(params);
+     }
+ 
+     return status;
+ }
+ 
+-sp<MediaSource> StagefrightRecorder::createAudioSource() {
++sp<MediaSource> GonkRecorder::createAudioSource() {
+ 
+     bool tunneledSource = false;
+     const char *tunnelMime;
+@@ -907,12 +788,6 @@
+         case AUDIO_ENCODER_AAC:
+             mime = MEDIA_MIMETYPE_AUDIO_AAC;
+             break;
+-        case AUDIO_ENCODER_EVRC:
+-            mime = MEDIA_MIMETYPE_AUDIO_EVRC;
+-            break;
+-        case AUDIO_ENCODER_QCELP:
+-            mime = MEDIA_MIMETYPE_AUDIO_QCELP;
+-            break;
+         default:
+             LOGE("Unknown audio encoder: %d", mAudioEncoder);
+             return NULL;
+@@ -931,36 +806,17 @@
+         encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+     }
+ 
+-    OMXClient client;
+-    CHECK_EQ(client.connect(), OK);
+-
++    // use direct OMX interface instead of connecting to
++    // mediaserver over binder calls
+     sp<MediaSource> audioEncoder =
+-        OMXCodec::Create(client.interface(), encMeta,
++        OMXCodec::Create(GetOMX(), encMeta,
+                          true /* createEncoder */, audioSource);
+     mAudioSourceNode = audioSource;
+ 
+     return audioEncoder;
+ }
+ 
+-status_t StagefrightRecorder::startAACRecording() {
+-    // FIXME:
+-    // Add support for OUTPUT_FORMAT_AAC_ADIF
+-    CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+-
+-    CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
+-    CHECK(mAudioSource != AUDIO_SOURCE_CNT);
+-
+-    mWriter = new AACWriter(mOutputFd);
+-    status_t status = startRawAudioRecording();
+-    if (status != OK) {
+-        mWriter.clear();
+-        mWriter = NULL;
+-    }
+-
+-    return status;
+-}
+-
+-status_t StagefrightRecorder::startAMRRecording() {
++status_t GonkRecorder::startAMRRecording() {
+     CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
+           mOutputFormat == OUTPUT_FORMAT_AMR_WB);
+ 
+@@ -971,28 +827,12 @@
+                     mAudioEncoder);
+             return BAD_VALUE;
+         }
+-        if (mSampleRate != 8000) {
+-            LOGE("Invalid sampling rate %d used for AMRNB recording",
+-                    mSampleRate);
+-            return BAD_VALUE;
+-        }
+     } else {  // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
+         if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
+             LOGE("Invlaid encoder %d used for AMRWB recording",
+                     mAudioEncoder);
+             return BAD_VALUE;
+         }
+-        if (mSampleRate != 16000) {
+-            LOGE("Invalid sample rate %d used for AMRWB recording",
+-                    mSampleRate);
+-            return BAD_VALUE;
+-        }
+-    }
+-
+-    if (mAudioChannels != 1) {
+-        LOGE("Invalid number of audio channels %d used for amr recording",
+-                mAudioChannels);
+-        return BAD_VALUE;
+     }
+ 
+     mWriter = new AMRWriter(mOutputFd);
+@@ -1004,7 +844,7 @@
+     return status;
+ }
+ 
+-status_t StagefrightRecorder::startRawAudioRecording() {
++status_t GonkRecorder::startRawAudioRecording() {
+     if (mAudioSource >= AUDIO_SOURCE_CNT) {
+         LOGE("Invalid audio source: %d", mAudioSource);
+         return BAD_VALUE;
+@@ -1035,62 +875,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::startFMA2DPWriter() {
+-    /* FM soc outputs at 48k */
+-	mSampleRate = 48000;
+-	mAudioChannels = 2;
+-	
+-    sp<MetaData> meta = new MetaData;
+-    meta->setInt32(kKeyChannelCount, mAudioChannels);
+-    meta->setInt32(kKeySampleRate, mSampleRate);
+-
+-    mWriter = new FMA2DPWriter();
+-    mWriter->setListener(mListener);
+-    mWriter->start(meta.get());
+-    return OK;
+-}
+-
+-status_t StagefrightRecorder::startRTPRecording() {
+-    CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
+-
+-    if ((mAudioSource != AUDIO_SOURCE_CNT
+-                && mVideoSource != VIDEO_SOURCE_LIST_END)
+-            || (mAudioSource == AUDIO_SOURCE_CNT
+-                && mVideoSource == VIDEO_SOURCE_LIST_END)) {
+-        // Must have exactly one source.
+-        return BAD_VALUE;
+-    }
+-
+-    if (mOutputFd < 0) {
+-        return BAD_VALUE;
+-    }
+-
+-    sp<MediaSource> source;
+-
+-    if (mAudioSource != AUDIO_SOURCE_CNT) {
+-        source = createAudioSource();
+-    } else {
+-
+-        sp<MediaSource> mediaSource;
+-        status_t err = setupMediaSource(&mediaSource);
+-        if (err != OK) {
+-            return err;
+-        }
+-
+-        err = setupVideoEncoder(mediaSource, mVideoBitRate, &source);
+-        if (err != OK) {
+-            return err;
+-        }
+-    }
+-
+-    mWriter = new ARTPWriter(mOutputFd);
+-    mWriter->addSource(source);
+-    mWriter->setListener(mListener);
+-
+-    return mWriter->start();
+-}
+-
+-status_t StagefrightRecorder::startMPEG2TSRecording() {
++status_t GonkRecorder::startMPEG2TSRecording() {
+     CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
+ 
+     sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
+@@ -1141,7 +926,7 @@
+     return mWriter->start();
+ }
+ 
+-void StagefrightRecorder::clipVideoFrameRate() {
++void GonkRecorder::clipVideoFrameRate() {
+     LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
+     int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
+                         "enc.vid.fps.min", mVideoEncoder);
+@@ -1158,7 +943,7 @@
+     }
+ }
+ 
+-void StagefrightRecorder::clipVideoBitRate() {
++void GonkRecorder::clipVideoBitRate() {
+     LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
+     int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
+                         "enc.vid.bps.min", mVideoEncoder);
+@@ -1175,7 +960,7 @@
+     }
+ }
+ 
+-void StagefrightRecorder::clipVideoFrameWidth() {
++void GonkRecorder::clipVideoFrameWidth() {
+     LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
+     int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
+                         "enc.vid.width.min", mVideoEncoder);
+@@ -1192,8 +977,7 @@
+     }
+ }
+ 
+-status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
+-    if (!mCaptureTimeLapse) {
++status_t GonkRecorder::checkVideoEncoderCapabilities() {
+         // Dont clip for time lapse capture as encoder will have enough
+         // time to encode because of slow capture rate of time lapse.
+         clipVideoBitRate();
+@@ -1201,13 +985,12 @@
+         clipVideoFrameWidth();
+         clipVideoFrameHeight();
+         setDefaultProfileIfNecessary();
+-    }
+     return OK;
+ }
+ 
+ // Set to use AVC baseline profile if the encoding parameters matches
+ // CAMCORDER_QUALITY_LOW profile; this is for the sake of MMS service.
+-void StagefrightRecorder::setDefaultProfileIfNecessary() {
++void GonkRecorder::setDefaultProfileIfNecessary() {
+     LOGV("setDefaultProfileIfNecessary");
+ 
+     camcorder_quality quality = CAMCORDER_QUALITY_LOW;
+@@ -1263,14 +1046,14 @@
+     }
+ }
+ 
+-status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
++status_t GonkRecorder::checkAudioEncoderCapabilities() {
+     clipAudioBitRate();
+     clipAudioSampleRate();
+     clipNumberOfAudioChannels();
+     return OK;
+ }
+ 
+-void StagefrightRecorder::clipAudioBitRate() {
++void GonkRecorder::clipAudioBitRate() {
+     LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
+ 
+     int minAudioBitRate =
+@@ -1292,7 +1075,7 @@
+     }
+ }
+ 
+-void StagefrightRecorder::clipAudioSampleRate() {
++void GonkRecorder::clipAudioSampleRate() {
+     LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
+ 
+     int minSampleRate =
+@@ -1314,7 +1097,7 @@
+     }
+ }
+ 
+-void StagefrightRecorder::clipNumberOfAudioChannels() {
++void GonkRecorder::clipNumberOfAudioChannels() {
+     LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
+ 
+     int minChannels =
+@@ -1336,7 +1119,7 @@
+     }
+ }
+ 
+-void StagefrightRecorder::clipVideoFrameHeight() {
++void GonkRecorder::clipVideoFrameHeight() {
+     LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
+     int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
+                         "enc.vid.height.min", mVideoEncoder);
+@@ -1354,61 +1137,26 @@
+ }
+ 
+ // Set up the appropriate MediaSource depending on the chosen option
+-status_t StagefrightRecorder::setupMediaSource(
++status_t GonkRecorder::setupMediaSource(
+                       sp<MediaSource> *mediaSource) {
+     if (mVideoSource == VIDEO_SOURCE_DEFAULT
+             || mVideoSource == VIDEO_SOURCE_CAMERA) {
+-        sp<CameraSource> cameraSource;
++        sp<GonkCameraSource> cameraSource;
+         status_t err = setupCameraSource(&cameraSource);
+         if (err != OK) {
+             return err;
+         }
+         *mediaSource = cameraSource;
+     } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
+-        // If using GRAlloc buffers, setup surfacemediasource.
+-        // Later a handle to that will be passed
+-        // to the client side when queried
+-        status_t err = setupSurfaceMediaSource();
+-        if (err != OK) {
+-            return err;
+-        }
+-        *mediaSource = mSurfaceMediaSource;
++        return BAD_VALUE;
+     } else {
+         return INVALID_OPERATION;
+     }
+     return OK;
+ }
+ 
+-// setupSurfaceMediaSource creates a source with the given
+-// width and height and framerate.
+-// TODO: This could go in a static function inside SurfaceMediaSource
+-// similar to that in CameraSource
+-status_t StagefrightRecorder::setupSurfaceMediaSource() {
+-    status_t err = OK;
+-    mSurfaceMediaSource = new SurfaceMediaSource(mVideoWidth, mVideoHeight);
+-    if (mSurfaceMediaSource == NULL) {
+-        return NO_INIT;
+-    }
+-
+-    if (mFrameRate == -1) {
+-        int32_t frameRate = 0;
+-        CHECK (mSurfaceMediaSource->getFormat()->findInt32(
+-                                        kKeyFrameRate, &frameRate));
+-        LOGI("Frame rate is not explicitly set. Use the current frame "
+-             "rate (%d fps)", frameRate);
+-        mFrameRate = frameRate;
+-    } else {
+-        err = mSurfaceMediaSource->setFrameRate(mFrameRate);
+-    }
+-    CHECK(mFrameRate != -1);
+-
+-    mIsMetaDataStoredInVideoBuffers =
+-        mSurfaceMediaSource->isMetaDataStoredInVideoBuffers();
+-    return err;
+-}
+-
+-status_t StagefrightRecorder::setupCameraSource(
+-        sp<CameraSource> *cameraSource) {
++status_t GonkRecorder::setupCameraSource(
++        sp<GonkCameraSource> *cameraSource) {
+     status_t err = OK;
+     if ((err = checkVideoEncoderCapabilities()) != OK) {
+         return err;
+@@ -1416,26 +1164,15 @@
+     Size videoSize;
+     videoSize.width = mVideoWidth;
+     videoSize.height = mVideoHeight;
+-    if (mCaptureTimeLapse) {
+-        mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
+-                mCamera, mCameraProxy, mCameraId,
+-                videoSize, mFrameRate, mPreviewSurface,
+-                mTimeBetweenTimeLapseFrameCaptureUs);
+-        *cameraSource = mCameraSourceTimeLapse;
+-    } else {
+-
+-        bool useMeta = true;
+-        char value[PROPERTY_VALUE_MAX];
+-        if (property_get("debug.camcorder.disablemeta", value, NULL) &&
++    bool useMeta = true;
++    char value[PROPERTY_VALUE_MAX];
++    if (property_get("debug.camcorder.disablemeta", value, NULL) &&
+             atoi(value)) {
+-            useMeta = false;
+-        }
+-        *cameraSource = CameraSource::CreateFromCamera(
+-                mCamera, mCameraProxy, mCameraId, videoSize, mFrameRate,
+-                mPreviewSurface, useMeta);
++      useMeta = false;
+     }
+-    mCamera.clear();
+-    mCameraProxy.clear();
++
++    *cameraSource = GonkCameraSource::Create(
++                mCameraHandle, videoSize, mFrameRate, useMeta);
+     if (*cameraSource == NULL) {
+         return UNKNOWN_ERROR;
+     }
+@@ -1465,7 +1202,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setupVideoEncoder(
++status_t GonkRecorder::setupVideoEncoder(
+         sp<MediaSource> cameraSource,
+         int32_t videoBitRate,
+         sp<MediaSource> *source) {
+@@ -1501,10 +1238,7 @@
+     CHECK(meta->findInt32(kKeyStride, &stride));
+     CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+     CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
+-    hfr = 0;
+-    if (!meta->findInt32(kKeyHFR, &hfr)) {
+-        LOGW("hfr not found, default to 0");
+-    }
++    CHECK(meta->findInt32(kKeyHFR, &hfr));
+ 
+     if(hfr) {
+       mMaxFileDurationUs = mMaxFileDurationUs * (hfr/mFrameRate);
+@@ -1598,30 +1332,17 @@
+         enc_meta->setInt32(kKey3D, is3D);
+     }
+ 
+-    OMXClient client;
+-    CHECK_EQ(client.connect(), OK);
+-
+     uint32_t encoder_flags = 0;
+     if (mIsMetaDataStoredInVideoBuffers) {
+         LOGW("Camera source supports metadata mode, create OMXCodec for metadata");
+         encoder_flags |= OMXCodec::kHardwareCodecsOnly;
+         encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
+-        if (property_get("ro.board.platform", value, "0")
+-            && (!strncmp(value, "msm7627", sizeof("msm7627") - 1))) {
+-            LOGW("msm7627 family of chipsets supports, only one buffer at a time");
+-            encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
+-        }
+-    }
+-
+-    // Do not wait for all the input buffers to become available.
+-    // This give timelapse video recording faster response in
+-    // receiving output from video encoder component.
+-    if (mCaptureTimeLapse) {
+         encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
+     }
+ 
+     sp<MediaSource> encoder = OMXCodec::Create(
+-            client.interface(), enc_meta,
++            GetOMX(),
++            enc_meta,
+             true /* createEncoder */, cameraSource,
+             NULL, encoder_flags);
+     if (encoder == NULL) {
+@@ -1638,7 +1359,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
++status_t GonkRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
+     status_t status = BAD_VALUE;
+     if (OK != (status = checkAudioEncoderCapabilities())) {
+         return status;
+@@ -1664,7 +1385,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::setupMPEG4Recording(
++status_t GonkRecorder::setupMPEG4Recording(
+         int outputFd,
+         int32_t videoWidth, int32_t videoHeight,
+         int32_t videoBitRate,
+@@ -1696,7 +1417,7 @@
+     // Audio source is added at the end if it exists.
+     // This help make sure that the "recoding" sound is suppressed for
+     // camcorder applications in the recorded files.
+-    if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
++    if (mAudioSource != AUDIO_SOURCE_CNT) {
+         err = setupAudioEncoder(writer);
+         if (err != OK) return err;
+         *totalBitRate += mAudioBitRate;
+@@ -1728,7 +1449,7 @@
+     return OK;
+ }
+ 
+-void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
++void GonkRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
+         sp<MetaData> *meta) {
+     (*meta)->setInt64(kKeyTime, startTimeUs);
+     (*meta)->setInt32(kKeyFileType, mOutputFormat);
+@@ -1752,7 +1473,7 @@
+     }
+ }
+ 
+-status_t StagefrightRecorder::startMPEG4Recording() {
++status_t GonkRecorder::startMPEG4Recording() {
+     int32_t totalBitRate;
+     status_t err = setupMPEG4Recording(
+             mOutputFd, mVideoWidth, mVideoHeight,
+@@ -1761,7 +1482,14 @@
+         return err;
+     }
+ 
+-    int64_t startTimeUs = systemTime() / 1000;
++    //systemTime() doesn't give correct time because
++    //HAVE_POSIX_CLOCKS is not defined for utils/Timers.cpp
++    //so, using clock_gettime directly
++#include <time.h>
++    struct timespec t;
++    clock_gettime(CLOCK_MONOTONIC, &t);
++    int64_t startTimeUs = int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
++    startTimeUs = startTimeUs / 1000;
+     sp<MetaData> meta = new MetaData;
+     setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
+ 
+@@ -1773,7 +1501,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::pause() {
++status_t GonkRecorder::pause() {
+     LOGV("pause");
+     if (mWriter == NULL) {
+         return UNKNOWN_ERROR;
+@@ -1782,31 +1510,16 @@
+ 
+     if (mStarted) {
+         mStarted = false;
+-
+-        uint32_t params = 0;
+-        if (mAudioSource != AUDIO_SOURCE_CNT) {
+-            params |= IMediaPlayerService::kBatteryDataTrackAudio;
+-        }
+-        if (mVideoSource != VIDEO_SOURCE_LIST_END) {
+-            params |= IMediaPlayerService::kBatteryDataTrackVideo;
+-        }
+-
+-        addBatteryData(params);
+     }
+ 
+ 
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::stop() {
++status_t GonkRecorder::stop() {
+     LOGV("stop");
+     status_t err = OK;
+ 
+-    if (mCaptureTimeLapse && mCameraSourceTimeLapse != NULL) {
+-        mCameraSourceTimeLapse->startQuickReadReturns();
+-        mCameraSourceTimeLapse = NULL;
+-    }
+-
+     if (mWriter != NULL) {
+         err = mWriter->stop();
+         mWriter.clear();
+@@ -1819,30 +1532,20 @@
+ 
+     if (mStarted) {
+         mStarted = false;
+-
+-        uint32_t params = 0;
+-        if (mAudioSource != AUDIO_SOURCE_CNT) {
+-            params |= IMediaPlayerService::kBatteryDataTrackAudio;
+-        }
+-        if (mVideoSource != VIDEO_SOURCE_LIST_END) {
+-            params |= IMediaPlayerService::kBatteryDataTrackVideo;
+-        }
+-
+-        addBatteryData(params);
+     }
+ 
+ 
+     return err;
+ }
+ 
+-status_t StagefrightRecorder::close() {
++status_t GonkRecorder::close() {
+     LOGV("close");
+     stop();
+ 
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::reset() {
++status_t GonkRecorder::reset() {
+     LOGV("reset");
+     stop();
+ 
+@@ -1858,9 +1561,9 @@
+     mVideoHeight   = 144;
+     mFrameRate     = -1;
+     mVideoBitRate  = 192000;
+-    mSampleRate    = 0;
+-    mAudioChannels = 0;
+-    mAudioBitRate  = 0;
++    mSampleRate    = 8000;
++    mAudioChannels = 1;
++    mAudioBitRate  = 12200;
+     mInterleaveDurationUs = 0;
+     mIFramesIntervalSec = 2;
+     mAudioSourceNode = 0;
+@@ -1875,9 +1578,6 @@
+     mMaxFileDurationUs = 0;
+     mMaxFileSizeBytes = 0;
+     mTrackEveryTimeDurationUs = 0;
+-    mCaptureTimeLapse = false;
+-    mTimeBetweenTimeLapseFrameCaptureUs = -1;
+-    mCameraSourceTimeLapse = NULL;
+     mIsMetaDataStoredInVideoBuffers = false;
+     mEncoderProfiles = MediaProfiles::getInstance();
+     mRotationDegrees = 0;
+@@ -1885,6 +1585,11 @@
+     mLongitudex10000 = -3600000;
+ 
+     mOutputFd = -1;
++    mCameraHandle = -1;
++    //TODO: May need to register a listener eventually
++    //if someone is interested in recorder events for now
++    //default to no listener registered
++    mListener = NULL;
+ 
+     // Disable Audio Encoding
+     char value[PROPERTY_VALUE_MAX];
+@@ -1894,7 +1599,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::getMaxAmplitude(int *max) {
++status_t GonkRecorder::getMaxAmplitude(int *max) {
+     LOGV("getMaxAmplitude");
+ 
+     if (max == NULL) {
+@@ -1911,7 +1616,7 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::dump(
++status_t GonkRecorder::dump(
+         int fd, const Vector<String16>& args) const {
+     LOGV("dump");
+     const size_t SIZE = 256;
+@@ -1958,6 +1663,8 @@
+     result.append(buffer);
+     snprintf(buffer, SIZE, "     Camera Id: %d\n", mCameraId);
+     result.append(buffer);
++    snprintf(buffer, SIZE, "     Camera Handle: %d\n", mCameraHandle);
++    result.append(buffer);
+     snprintf(buffer, SIZE, "     Start time offset (ms): %d\n", mStartTimeOffsetMs);
+     result.append(buffer);
+     snprintf(buffer, SIZE, "     Encoder: %d\n", mVideoEncoder);
+@@ -1978,45 +1685,12 @@
+     return OK;
+ }
+ 
+-status_t StagefrightRecorder::startExtendedRecording() {
+-    CHECK(mOutputFormat == OUTPUT_FORMAT_QCP);
+-
+-    if (mSampleRate != 8000) {
+-        LOGE("Invalid sampling rate %d used for recording",
+-             mSampleRate);
+-        return BAD_VALUE;
+-    }
+-    if (mAudioChannels != 1) {
+-        LOGE("Invalid number of audio channels %d used for recording",
+-                mAudioChannels);
+-        return BAD_VALUE;
+-    }
+-
+-    if (mAudioSource >= AUDIO_SOURCE_CNT) {
+-        LOGE("Invalid audio source: %d", mAudioSource);
+-        return BAD_VALUE;
+-    }
+-
+-    sp<MediaSource> audioEncoder = createAudioSource();
+-
+-    if (audioEncoder == NULL) {
+-        LOGE("AudioEncoder NULL");
+-        return UNKNOWN_ERROR;
+-    }
+-
+-    mWriter = new ExtendedWriter(dup(mOutputFd));
+-    mWriter->addSource(audioEncoder);
+-
+-    if (mMaxFileDurationUs != 0) {
+-        mWriter->setMaxFileDuration(mMaxFileDurationUs);
+-    }
+-    if (mMaxFileSizeBytes != 0) {
+-        mWriter->setMaxFileSize(mMaxFileSizeBytes);
+-    }
+-    mWriter->setListener(mListener);
+-    mWriter->start();
+-
+-    return OK;
++status_t GonkRecorder::setCameraHandle(int32_t handle) {
++  if (handle < 0) {
++    return BAD_VALUE;
++  }
++  mCameraHandle = handle;
++  return OK;
+ }
+ 
+ }  // namespace android
+diff --git a/GonkRecorder.h b/GonkRecorder.h
+index dba6110..fa948af 100644
+--- a/GonkRecorder.h
++++ b/GonkRecorder.h
+@@ -14,11 +14,11 @@
+  * limitations under the License.
+  */
+ 
+-#ifndef STAGEFRIGHT_RECORDER_H_
++#ifndef GONK_RECORDER_H_
+ 
+-#define STAGEFRIGHT_RECORDER_H_
++#define GONK_RECORDER_H_
+ 
+-#include <media/MediaRecorderBase.h>
++#include <media/mediarecorder.h>
+ #include <camera/CameraParameters.h>
+ #include <utils/String8.h>
+ 
+@@ -26,21 +26,16 @@
+ 
+ namespace android {
+ 
+-class Camera;
+-class ICameraRecordingProxy;
+-class CameraSource;
+-class CameraSourceTimeLapse;
++class GonkCameraSource;
+ struct MediaSource;
+ struct MediaWriter;
+ class MetaData;
+ struct AudioSource;
+ class MediaProfiles;
+-class ISurfaceTexture;
+-class SurfaceMediaSource;
+ 
+-struct StagefrightRecorder : public MediaRecorderBase {
+-    StagefrightRecorder();
+-    virtual ~StagefrightRecorder();
++struct GonkRecorder {
++    GonkRecorder();
++    virtual ~GonkRecorder();
+ 
+     virtual status_t init();
+     virtual status_t setAudioSource(audio_source_t as);
+@@ -50,11 +45,10 @@
+     virtual status_t setVideoEncoder(video_encoder ve);
+     virtual status_t setVideoSize(int width, int height);
+     virtual status_t setVideoFrameRate(int frames_per_second);
+-    virtual status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
+-    virtual status_t setPreviewSurface(const sp<Surface>& surface);
+     virtual status_t setOutputFile(const char *path);
+     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
+     virtual status_t setParameters(const String8& params);
++    virtual status_t setCameraHandle(int32_t handle);
+     virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
+     virtual status_t prepare();
+     virtual status_t start();
+@@ -65,12 +59,8 @@
+     virtual status_t getMaxAmplitude(int *max);
+     virtual status_t dump(int fd, const Vector<String16>& args) const;
+     // Querying a SurfaceMediaSourcer
+-    virtual sp<ISurfaceTexture> querySurfaceMediaSource() const;
+ 
+ private:
+-    sp<ICamera> mCamera;
+-    sp<ICameraRecordingProxy> mCameraProxy;
+-    sp<Surface> mPreviewSurface;
+     sp<IMediaRecorderClient> mListener;
+     sp<MediaWriter> mWriter;
+     int mOutputFd;
+@@ -104,11 +94,6 @@
+     int32_t mLongitudex10000;
+     int32_t mStartTimeOffsetMs;
+ 
+-    bool mCaptureTimeLapse;
+-    int64_t mTimeBetweenTimeLapseFrameCaptureUs;
+-    sp<CameraSourceTimeLapse> mCameraSourceTimeLapse;
+-
+-
+     String8 mParams;
+ 
+     bool mIsMetaDataStoredInVideoBuffers;
+@@ -119,8 +104,8 @@
+     // An <ISurfaceTexture> pointer
+     // will be sent to the client side using which the
+     // frame buffers will be queued and dequeued
+-    sp<SurfaceMediaSource> mSurfaceMediaSource;
+     bool mDisableAudio;
++    int32_t mCameraHandle;
+ 
+     status_t setupMPEG4Recording(
+         int outputFd,
+@@ -132,10 +117,7 @@
+         sp<MetaData> *meta);
+     status_t startMPEG4Recording();
+     status_t startAMRRecording();
+-    status_t startFMA2DPWriter();
+-    status_t startAACRecording();
+     status_t startRawAudioRecording();
+-    status_t startRTPRecording();
+     status_t startMPEG2TSRecording();
+     sp<MediaSource> createAudioSource();
+     status_t checkVideoEncoderCapabilities();
+@@ -144,9 +126,8 @@
+     // source (CameraSource or SurfaceMediaSource)
+     // depending on the videosource type
+     status_t setupMediaSource(sp<MediaSource> *mediaSource);
+-    status_t setupCameraSource(sp<CameraSource> *cameraSource);
++    status_t setupCameraSource(sp<GonkCameraSource> *cameraSource);
+     // setup the surfacemediasource for the encoder
+-    status_t setupSurfaceMediaSource();
+ 
+     status_t setupAudioEncoder(const sp<MediaWriter>& writer);
+     status_t setupVideoEncoder(
+@@ -160,8 +141,6 @@
+     status_t setParamAudioNumberOfChannels(int32_t channles);
+     status_t setParamAudioSamplingRate(int32_t sampleRate);
+     status_t setParamAudioTimeScale(int32_t timeScale);
+-    status_t setParamTimeLapseEnable(int32_t timeLapseEnable);
+-    status_t setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs);
+     status_t setParamVideoEncodingBitRate(int32_t bitRate);
+     status_t setParamVideoIFramesInterval(int32_t seconds);
+     status_t setParamVideoEncoderProfile(int32_t profile);
+@@ -186,14 +165,10 @@
+     void clipNumberOfAudioChannels();
+     void setDefaultProfileIfNecessary();
+ 
+-
+-    StagefrightRecorder(const StagefrightRecorder &);
+-    StagefrightRecorder &operator=(const StagefrightRecorder &);
+-
+-    /* extension */
+-    status_t startExtendedRecording();
++    GonkRecorder(const GonkRecorder &);
++    GonkRecorder &operator=(const GonkRecorder &);
+ };
+ 
+ }  // namespace android
+ 
+-#endif  // STAGEFRIGHT_RECORDER_H_
++#endif  // GONK_RECORDER_H_
new file mode 100644
--- /dev/null
+++ b/dom/camera/update.sh
@@ -0,0 +1,14 @@
+# Usage: ./update.sh <android_ics_os_src_directory>
+#
+# Copies the needed files from the directory containing the original
+# Android ICS OS source and applies the B2G specific changes for the
+# camcorder functionality in B2G.
+cp $1/frameworks/base/media/libmediaplayerservice/StagefrightRecorder.cpp ./GonkRecorder.cpp
+cp $1/frameworks/base/media/libmediaplayerservice/StagefrightRecorder.h ./GonkRecorder.h
+cp $1/frameworks/base/media/libstagefright/CameraSource.cpp ./GonkCameraSource.cpp
+cp $1/frameworks/base/include/media/stagefright/CameraSource.h ./GonkCameraSource.h
+cp $1/frameworks/base/media/libmedia/AudioParameter.cpp ./AudioParameter.cpp
+cp $1/frameworks/base/include/camera/Camera.h ./GonkCameraListener.h
+patch -p1 <update.patch
+# If you import CAF sources, you also need to apply update2.patch
+patch -p1 <update2.patch
new file mode 100644
--- /dev/null
+++ b/dom/camera/update2.patch
@@ -0,0 +1,163 @@
+diff --git a/dom/camera/GonkCameraSource.cpp b/dom/camera/GonkCameraSource.cpp
+--- a/dom/camera/GonkCameraSource.cpp
++++ b/dom/camera/GonkCameraSource.cpp
+@@ -492,21 +492,17 @@ status_t GonkCameraSource::init(
+     mMeta = new MetaData;
+     mMeta->setCString(kKeyMIMEType,  MEDIA_MIMETYPE_VIDEO_RAW);
+     mMeta->setInt32(kKeyColorFormat, mColorFormat);
+     mMeta->setInt32(kKeyWidth,       mVideoSize.width);
+     mMeta->setInt32(kKeyHeight,      mVideoSize.height);
+     mMeta->setInt32(kKeyStride,      mVideoSize.width);
+     mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
+     mMeta->setInt32(kKeyFrameRate,   mVideoFrameRate);
+-    mMeta->setInt32(kKeyHFR, hfr);
+ 
+-    if (want3D) {
+-        mMeta->setInt32(kKey3D, !0);
+-    }
+     return OK;
+ }
+ 
+ GonkCameraSource::~GonkCameraSource() {
+     if (mStarted) {
+         stop();
+     } else if (mInitCheck == OK) {
+         // Camera is initialized but because start() is never called,
+diff --git a/dom/camera/GonkRecorder.cpp b/dom/camera/GonkRecorder.cpp
+--- a/dom/camera/GonkRecorder.cpp
++++ b/dom/camera/GonkRecorder.cpp
+@@ -716,56 +716,16 @@ status_t GonkRecorder::start() {
+         mStarted = true;
+     }
+ 
+     return status;
+ }
+ 
+ sp<MediaSource> GonkRecorder::createAudioSource() {
+ 
+-    bool tunneledSource = false;
+-    const char *tunnelMime;
+-    {
+-        AudioParameter param;
+-        String8 key("tunneled-input-formats");
+-        param.add( key, String8("get") );
+-        String8 valueStr = AudioSystem::getParameters( 0, param.toString());
+-        AudioParameter result(valueStr);
+-        int value;
+-        if ( mAudioEncoder == AUDIO_ENCODER_AMR_NB &&
+-            result.getInt(String8("AMR"),value) == NO_ERROR ) {
+-            tunneledSource = true;
+-            tunnelMime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+-        }
+-        else if ( mAudioEncoder == AUDIO_ENCODER_QCELP &&
+-            result.getInt(String8("QCELP"),value) == NO_ERROR ) {
+-            tunneledSource = true;
+-            tunnelMime = MEDIA_MIMETYPE_AUDIO_QCELP;
+-        }
+-        else if ( mAudioEncoder == AUDIO_ENCODER_EVRC &&
+-            result.getInt(String8("EVRC"),value) == NO_ERROR ) {
+-            tunneledSource = true;
+-            tunnelMime = MEDIA_MIMETYPE_AUDIO_EVRC;
+-        }
+-    }
+-
+-    if ( tunneledSource ) {
+-        sp<AudioSource> audioSource = NULL;
+-        sp<MetaData> meta = new MetaData;
+-        meta->setInt32(kKeyChannelCount, mAudioChannels);
+-        meta->setInt32(kKeySampleRate, mSampleRate);
+-        meta->setInt32(kKeyBitRate, mAudioBitRate);
+-        if (mAudioTimeScale > 0) {
+-            meta->setInt32(kKeyTimeScale, mAudioTimeScale);
+-        }
+-        meta->setCString( kKeyMIMEType, tunnelMime );
+-        audioSource = new AudioSource( mAudioSource, meta);
+-        return audioSource->initCheck( ) == OK ? audioSource : NULL;
+-    }
+-
+     sp<AudioSource> audioSource =
+         new AudioSource(
+                 mAudioSource,
+                 mSampleRate,
+                 mAudioChannels);
+ 
+     status_t err = audioSource->initCheck();
+ 
+@@ -1226,56 +1186,33 @@ status_t GonkRecorder::setupVideoEncoder
+ 
+         default:
+             CHECK(!"Should not be here, unsupported video encoding.");
+             break;
+     }
+ 
+     sp<MetaData> meta = cameraSource->getFormat();
+ 
+-    int32_t width, height, stride, sliceHeight, colorFormat, hfr, is3D;
++    int32_t width, height, stride, sliceHeight, colorFormat;
+     CHECK(meta->findInt32(kKeyWidth, &width));
+     CHECK(meta->findInt32(kKeyHeight, &height));
+     CHECK(meta->findInt32(kKeyStride, &stride));
+     CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+     CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
+-    CHECK(meta->findInt32(kKeyHFR, &hfr));
+-
+-    if(hfr) {
+-      mMaxFileDurationUs = mMaxFileDurationUs * (hfr/mFrameRate);
+-    }
+-
+ 
+     enc_meta->setInt32(kKeyWidth, width);
+     enc_meta->setInt32(kKeyHeight, height);
+     enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
+     enc_meta->setInt32(kKeyStride, stride);
+     enc_meta->setInt32(kKeySliceHeight, sliceHeight);
+     enc_meta->setInt32(kKeyColorFormat, colorFormat);
+-    enc_meta->setInt32(kKeyHFR, hfr);
+     if (mVideoTimeScale > 0) {
+         enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+     }
+ 
+-    char mDeviceName[100];
+-    property_get("ro.board.platform",mDeviceName,"0");
+-    if(!strncmp(mDeviceName, "msm7627a", 8)) {
+-      if(hfr && (width * height > 432*240)) {
+-        LOGE("HFR mode is supported only upto WQVGA resolution");
+-        return INVALID_OPERATION;
+-      }
+-    }
+-    else {
+-      if(hfr && ((mVideoEncoder != VIDEO_ENCODER_H264) || (width * height > 800*480))) {
+-        LOGE("HFR mode is supported only upto WVGA and H264 codec.");
+-        return INVALID_OPERATION;
+-      }
+-    }
+-
+-
+     /*
+      * can set profile from the app as a parameter.
+      * For the mean time, set from shell
+      */
+ 
+     char value[PROPERTY_VALUE_MAX];
+     bool customProfile = false;
+ 
+@@ -1322,19 +1259,16 @@ status_t GonkRecorder::setupVideoEncoder
+     }
+ 
+     if (mVideoEncoderProfile != -1) {
+         enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
+     }
+     if (mVideoEncoderLevel != -1) {
+         enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
+     }
+-    if (meta->findInt32(kKey3D, &is3D)) {
+-        enc_meta->setInt32(kKey3D, is3D);
+-    }
+ 
+     uint32_t encoder_flags = 0;
+     if (mIsMetaDataStoredInVideoBuffers) {
+         LOGW("Camera source supports metadata mode, create OMXCodec for metadata");
+         encoder_flags |= OMXCodec::kHardwareCodecsOnly;
+         encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
+         encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
+     }
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -50,17 +50,18 @@ DeviceStorageRequestChild::Recv__delete_
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
       nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
 
-      jsval result = InterfaceToJsval(mRequest->GetOwner(), blob, &NS_GET_IID(nsIDOMBlob));
+      nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
+      jsval result = InterfaceToJsval(mRequest->GetOwner(), file, &NS_GET_IID(nsIDOMFile));
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TStatStorageResponse:
     {
       StatStorageResponse r = aValue;
 
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1909,16 +1909,27 @@ nsDOMDeviceStorage::Stat(nsIDOMDOMReques
                                                      mPrincipal,
                                                      dsf,
                                                      request);
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMDeviceStorage::GetRootDirectory(nsIFile** aRootDirectory)
+{
+  if (!mRootDirectory) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIFile> file;
+  return mRootDirectory->Clone(aRootDirectory);
+}
+
+NS_IMETHODIMP
 nsDOMDeviceStorage::Enumerate(const JS::Value & aName,
                              const JS::Value & aOptions,
                              JSContext* aCx,
                              uint8_t aArgc,
                              nsIDOMDeviceStorageCursor** aRetval)
 {
   return EnumerateInternal(aName, aOptions, aCx, aArgc, false, aRetval);
 }
--- a/dom/icc/interfaces/SimToolKit.idl
+++ b/dom/icc/interfaces/SimToolKit.idl
@@ -250,16 +250,104 @@ dictionary MozStkSetUpEventList
    * When this valus is null, means an indication to remove the existing list
    * of events in ME.
    *
    * @see nsIDOMMozIccManager.STK_EVENT_TYPE_*
    */
    jsval eventList; // unsigned short []
 };
 
+dictionary MozStkLocationInfo
+{
+  /**
+   * Mobile Country Code (MCC) of the current serving operator.
+   */
+  unsigned short mcc;
+
+  /**
+   * Mobile Network Code (MNC) of the current serving operator.
+   */
+  unsigned short mnc;
+
+  /**
+   * Mobile Location Area Code (LAC) for the current serving operator.
+   */
+  unsigned short gsmLocationAreaCode;
+
+  /**
+   * Mobile Cell ID for the current serving operator.
+   */
+  unsigned long gsmCellId;
+};
+
+dictionary MozStkDuration
+{
+  /**
+   * Time unit used, should be one of STK_TIME_UNIT_*.
+   */
+  unsigned short timeUnit;
+
+  /**
+   * The length of time required, expressed in timeUnit.
+   */
+  octet timeInterval;
+};
+
+dictionary MozStkPlayTone
+{
+  /**
+   * Text String.
+   */
+  DOMString text;
+
+  /**
+   * One of STK_TONE_TYPE_*.
+   */
+  unsigned short tone;
+
+  /**
+   * The length of time for which the ME shall generate the tone.
+   *
+   * @see MozStkDuration
+   */
+  jsval duration;
+
+  /**
+   * Need to vibrate or not.
+   * true: vibrate alert, if available, with the tone.
+   * false: use of vibrate alert is up to the ME.
+   */
+  boolean isVibrate;
+};
+
+dictionary MozStkLocationEvent
+{
+  /**
+   * The type of this event.
+   * It shall be nsIDOMMozIccManager.STK_EVENT_TYPE_LOCATION_STATUS;
+   */
+  unsigned short eventType;
+
+  /**
+   * Indicate current service state of the MS with one of the values listed
+   * below:
+   *  - nsIDOMMozIccManager.STK_SERVICE_STATE_NORMAL
+   *  - nsIDOMMozIccManager.STK_SERVICE_STATE_LIMITED
+   *  - nsIDOMMozIccManager.STK_SERVICE_STATE_UNAVAILABLE
+   */
+  unsigned short locationStatus;
+
+  /**
+   * See MozStkLocationInfo.
+   * This value shall only be provided if the locationStatus indicates
+   * 'STK_SERVICE_STATE_NORMAL'.
+   */
+  jsval locationInfo;
+};
+
 dictionary MozStkCommand
 {
   /**
    * The number of command issued by ICC. And it is assigned
    * by ICC may take any hexadecimal value betweean '01' and 'FE'.
    *
    * @see TS 11.14, clause 6.5.1
    */
@@ -301,16 +389,32 @@ dictionary MozStkCommand
    *
    * When typeOfCommand is
    * - STK_CMD_SET_UP_CALL
    * options is MozStkSetUpCall.
    *
    * When typeOfCommand is
    * - STK_CMD_SET_UP_EVENT_LIST
    * options is MozStkSetUpEventList.
+   *
+   * When typeOfCommand is
+   * - STK_CMD_PLAY_TONE
+   * options is MozStkPlayTone.
+   *
+   * When typeOfCommand is
+   * - STK_CMD_POLL_INTERVAL
+   * options is MozStkDuration.
+   *
+   * When typeOfCommand is
+   * - STK_CMD_POLL_OFF
+   * options is null.
+   *
+   * When typeOfCommand is
+   * - STK_CMD_REFRESH
+   * options is null.
    */
   jsval options;
 };
 
 [scriptable, builtinclass, uuid(06bbc6fa-9b59-4db6-b66b-3b26f9c379df)]
 interface nsIDOMMozStkCommandEvent : nsIDOMEvent
 {
   /**
--- a/dom/icc/interfaces/nsIDOMIccManager.idl
+++ b/dom/icc/interfaces/nsIDOMIccManager.idl
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMEventTarget.idl"
 #include "SimToolKit.idl"
 
 interface nsIDOMEventListener;
 
-[scriptable, builtinclass, uuid(2eace3f9-6aa4-491b-820e-7d69ce7b3f02)]
+[scriptable, builtinclass, uuid(9d898c66-3485-4cd5-ab8d-92ef2988887b)]
 interface nsIDOMMozIccManager : nsIDOMEventTarget
 {
   /**
    * STK Menu Presentation types.
    */
   const unsigned short STK_MENU_TYPE_NOT_SPECIFIED      = 0x00;
   const unsigned short STK_MENU_TYPE_DATA_VALUES        = 0x01;
   const unsigned short STK_MENU_TYPE_NAVIGATION_OPTIONS = 0x03;
@@ -25,23 +25,26 @@ interface nsIDOMMozIccManager : nsIDOMEv
   const unsigned short STK_BROWSER_MODE_USING_NEW_BROWSER              = 0x03;
 
   /**
    * STK Proactive commands.
    *
    * @see TS 11.14, clause 13.4
    */
   const unsigned short STK_CMD_REFRESH               = 0x01;
+  const unsigned short STK_CMD_POLL_INTERVAL         = 0x03;
+  const unsigned short STK_CMD_POLL_OFF              = 0x04;
   const unsigned short STK_CMD_SET_UP_EVENT_LIST     = 0x05;
   const unsigned short STK_CMD_SET_UP_CALL           = 0x10;
   const unsigned short STK_CMD_SEND_SS               = 0x11;
   const unsigned short STK_CMD_SEND_USSD             = 0x12;
   const unsigned short STK_CMD_SEND_SMS              = 0x13;
   const unsigned short STK_CMD_SEND_DTMF             = 0x14;
   const unsigned short STK_CMD_LAUNCH_BROWSER        = 0x15;
+  const unsigned short STK_CMD_PLAY_TONE             = 0x20;
   const unsigned short STK_CMD_DISPLAY_TEXT          = 0x21;
   const unsigned short STK_CMD_GET_INKEY             = 0x22;
   const unsigned short STK_CMD_GET_INPUT             = 0x23;
   const unsigned short STK_CMD_SELECT_ITEM           = 0x24;
   const unsigned short STK_CMD_SET_UP_MENU           = 0x25;
   const unsigned short STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28;
 
   /**
@@ -157,16 +160,45 @@ interface nsIDOMMozIccManager : nsIDOMEv
    const unsigned short STK_EVENT_TYPE_CHANNEL_STATUS                   = 0x0a;
    const unsigned short STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED = 0x0b;
    const unsigned short STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED        = 0x0c;
    const unsigned short STK_EVENT_TYPE_LOCAL_CONNECTION                 = 0x0d;
    const unsigned short STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED      = 0x0e;
    const unsigned short STK_EVENT_TYPE_BROWSING_STATUS                  = 0x0f;
    const unsigned short STK_EVENT_TYPE_FRAMES_INFORMATION_CHANGED       = 0x10;
 
+   /**
+    * The service state of STK Location Status.
+    */
+   const unsigned short STK_SERVICE_STATE_NORMAL      = 0x00;
+   const unsigned short STK_SERVICE_STATE_LIMITED     = 0x01;
+   const unsigned short STK_SERVICE_STATE_UNAVAILABLE = 0x02;
+
+  /**
+   * Tone type.
+   */
+  const unsigned short STK_TONE_TYPE_DIAL_TONE                = 0x01;
+  const unsigned short STK_TONE_TYPE_CALLED_SUBSCRIBER_BUSY   = 0x02;
+  const unsigned short STK_TONE_TYPE_CONGESTION               = 0x03;
+  const unsigned short STK_TONE_TYPE_RADIO_PATH_ACK           = 0x04;
+  const unsigned short STK_TONE_TYPE_RADIO_PATH_NOT_AVAILABLE = 0x05;
+  const unsigned short STK_TONE_TYPE_ERROR                    = 0x06;
+  const unsigned short STK_TONE_TYPE_CALL_WAITING_TONE        = 0x07;
+  const unsigned short STK_TONE_TYPE_RINGING_TONE             = 0x08;
+  const unsigned short STK_TONE_TYPE_GENERAL_BEEP             = 0x10;
+  const unsigned short STK_TONE_TYPE_POSITIVE_ACK_TONE        = 0x11;
+  const unsigned short STK_TONE_TYPE_NEGATIVE_ACK_TONE        = 0x12;
+
+  /**
+   * Time unit
+   */
+  const unsigned short STK_TIME_UNIT_MINUTE       = 0x00;
+  const unsigned short STK_TIME_UNIT_SECOND       = 0x01;
+  const unsigned short STK_TIME_UNIT_TENTH_SECOND = 0x02;
+
   /**
    * Send the response back to ICC after an attempt to execute STK Proactive
    * Command.
    *
    * @param command
    *        Command received from ICC. See MozStkCommand.
    * @param response
    *        The response that will be sent to ICC.
@@ -181,16 +213,26 @@ interface nsIDOMMozIccManager : nsIDOMEv
    *        The identifier of the item selected by user.
    * @param helpRequested
    *        true if user requests to provide help information, false otherwise.
    */
   void sendStkMenuSelection(in unsigned short itemIdentifier,
                             in boolean        helpRequested);
 
   /**
+   * Send "Event Download" Envelope command to ICC.
+   * ICC will not respond with any data for this command.
+   *
+   * @param event
+   *        one of events below:
+   *        - MozStkLocationEvent
+   */
+  void sendStkEventDownload(in jsval event);
+
+  /**
    * The 'stkcommand' event is notified whenever STK Proactive Command is
    * issued from ICC.
    */
   [implicit_jscontext] attribute jsval onstkcommand;
 
   /**
    * 'stksessionend' event is notified whenever STK Session is terminated by
    * ICC.
--- a/dom/icc/src/IccManager.cpp
+++ b/dom/icc/src/IccManager.cpp
@@ -132,16 +132,27 @@ IccManager::SendStkMenuSelection(uint16_
   if (!mProvider) {
     return NS_ERROR_FAILURE;
   }
 
   mProvider->SendStkMenuSelection(GetOwner(), aItemIdentifier, aHelpRequested);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+IccManager::SendStkEventDownload(const JS::Value& aEvent)
+{
+  if (!mProvider) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mProvider->SendStkEventDownload(GetOwner(), aEvent);
+  return NS_OK;
+}
+
 nsresult
 IccManager::InternalDispatchEvent(const nsAString& aType)
 {
   nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nullptr, nullptr);
   nsresult rv = event->InitEvent(aType, false, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = event->SetTrusted(true);
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -35,17 +35,17 @@ interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 interface nsIDOMClientRect;
 interface nsIURI;
 
-[scriptable, uuid(90d8e97b-2c61-4c05-9f1c-e568d22f5bdc)]
+[scriptable, uuid(47405734-D827-44AE-AC01-EF10E80F5D04)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -693,16 +693,24 @@ interface nsIDOMWindowUtils : nsISupport
   readonly attribute unsigned long IMEStatus;
 
   /**
    * Get the number of screen pixels per CSS pixel.
    */
   readonly attribute float screenPixelsPerCSSPixel;
 
   /**
+   * Get the current zoom factor.
+   * This is _approximately_ the same as nsIMarkupDocumentViewer.fullZoom,
+   * but takes into account Gecko's quantization of the zoom factor, which is
+   * implemented by adjusting the (integer) number of appUnits per devPixel.
+   */
+  readonly attribute float fullZoom;
+
+  /**
    * Dispatches aEvent via the nsIPresShell object of the window's document.
    * The event is dispatched to aTarget, which should be an object
    * which implements nsIContent interface (#element, #text, etc).
    *
    * Cannot be accessed from unprivileged context (not
    * content-accessible) Will throw a DOM security error if called
    * without UniversalXPConnect privileges.
    *
--- a/dom/interfaces/devicestorage/nsIDOMDeviceStorage.idl
+++ b/dom/interfaces/devicestorage/nsIDOMDeviceStorage.idl
@@ -4,23 +4,24 @@
 
 #include "domstubs.idl"
 #include "nsIDOMEventTarget.idl"
 interface nsIDOMBlob;
 interface nsIDOMDOMRequest;
 interface nsIDOMDeviceStorageCursor;
 interface nsIDOMDeviceStorageChangeEvent;
 interface nsIDOMEventListener;
+interface nsIFile;
 
 dictionary DeviceStorageEnumerationParameters
 {
   jsval since;
 };
 
-[scriptable, uuid(7efbe025-3a8a-4151-9257-3e8c941dc099), builtinclass]
+[scriptable, uuid(7f69936f-2948-4733-ba41-c7e1d657a88b), builtinclass]
 interface nsIDOMDeviceStorage : nsIDOMEventTarget
 {
     [implicit_jscontext] attribute jsval onchange;
     nsIDOMDOMRequest add(in nsIDOMBlob aBlob);
     nsIDOMDOMRequest addNamed(in nsIDOMBlob aBlob, in DOMString aName);
 
     [implicit_jscontext]
     nsIDOMDOMRequest get(in jsval aName);
@@ -33,9 +34,11 @@ interface nsIDOMDeviceStorage : nsIDOMEv
 
     [optional_argc, implicit_jscontext]
     nsIDOMDeviceStorageCursor enumerate([optional] in jsval aName, /* DeviceStorageEnumerationParameters */ [optional] in jsval options);
 
     [optional_argc, implicit_jscontext]
     nsIDOMDeviceStorageCursor enumerateEditable([optional] in jsval aName, /* DeviceStorageEnumerationParameters */ [optional] in jsval options);
 
     nsIDOMDOMRequest stat();
+
+    [noscript] readonly attribute nsIFile rootDirectory;
 };
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -261,35 +261,41 @@ parent:
      * We know for sure that content has either preventDefaulted or not
      * preventDefaulted. This applies to an entire batch of touch events. It is
      * expected that, if there are any DOM touch listeners, touch events will be
      * batched and only processed for panning and zooming if content does not
      * preventDefault.
      */
     ContentReceivedTouch(bool aPreventDefault);
 
+    /**
+     * Updates any zoom constraints on the parent and anything tied to it. This
+     * is useful for control logic that resides outside of the remote browser.
+     */
+    UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
+
     __delete__();
 
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
      * |Show()| and |Move()| take IntSizes rather than Rects because
      * content processes always render to a virtual <0, 0> top-left
      * point.
      */
     Show(nsIntSize size);
 
     LoadURL(nsCString uri);
 
-    UpdateDimensions(nsRect rect, nsIntSize size);
+    UpdateDimensions(nsRect rect, nsIntSize size) compress;
 
-    UpdateFrame(FrameMetrics frame);
+    UpdateFrame(FrameMetrics frame) compress;
 
     /**
      * Requests handling of a double tap. |point| is in CSS pixels, relative to
      * the scroll offset. This message is expected to round-trip back to
      * ZoomToRect() with a rect indicating where we should zoom to.
      */
     HandleDoubleTap(nsIntPoint point);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -13,31 +13,34 @@
 #include "ContentChild.h"
 #include "IndexedDBChild.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/IntentionalCrash.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/PContentChild.h"
 #include "mozilla/dom/PContentDialogChild.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
+#include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/PLayersChild.h"
 #include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 #include "mozIApplication.h"
 #include "nsComponentManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsEmbedCID.h"
 #include "nsEventListenerManager.h"
+#include "nsGenericElement.h"
 #include "nsIAppsService.h"
 #include "nsIBaseWindow.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMClassInfo.h"
+#include "nsIDOMElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIJSContextStack.h"
@@ -45,16 +48,18 @@
 #include "nsISSLStatusProvider.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIServiceManager.h"
 #include "nsISupportsImpl.h"
 #include "nsIURI.h"
+#include "nsIURIFixup.h"
+#include "nsCDefaultURIFixup.h"
 #include "nsIView.h"
 #include "nsIWebBrowser.h"
 #include "nsIWebBrowserFocus.h"
 #include "nsIWebBrowserSetup.h"
 #include "nsIWebProgress.h"
 #include "nsIXPCSecurityManager.h"
 #include "nsInterfaceHashtable.h"
 #include "nsPIDOMWindow.h"
@@ -80,16 +85,22 @@ using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::widget;
 
 NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
 
+static const nsIntSize kDefaultViewportSize(980, 480);
+
+static const char CANCEL_DEFAULT_PAN_ZOOM[] = "cancel-default-pan-zoom";
+static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
+static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
+
 NS_IMETHODIMP
 ContentListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   RemoteDOMEvent remoteEvent;
   remoteEvent.mEvent = do_QueryInterface(aEvent);
   NS_ENSURE_STATE(remoteEvent.mEvent);
   mTabChild->SendEvent(remoteEvent);
   return NS_OK;
@@ -146,52 +157,322 @@ TabChild::Create(uint32_t aChromeFlags,
 
 
 TabChild::TabChild(uint32_t aChromeFlags, bool aIsBrowserElement,
                    uint32_t aAppId)
   : mRemoteFrame(nullptr)
   , mTabChildGlobal(nullptr)
   , mChromeFlags(aChromeFlags)
   , mOuterRect(0, 0, 0, 0)
+  , mInnerSize(0, 0)
+  , mOldViewportWidth(0.0f)
   , mLastBackgroundColor(NS_RGB(255, 255, 255))
   , mAppId(aAppId)
   , mDidFakeShow(false)
   , mIsBrowserElement(aIsBrowserElement)
   , mNotified(false)
+  , mContentDocumentIsDisplayed(false)
   , mTriedBrowserInit(false)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
-nsresult
+NS_IMETHODIMP
+TabChild::HandleEvent(nsIDOMEvent* aEvent)
+{
+  nsAutoString eventType;
+  aEvent->GetType(eventType);
+  if (eventType.EqualsLiteral("DOMMetaAdded")) {
+    // This meta data may or may not have been a meta viewport tag. If it was,
+    // we should handle it immediately.
+    HandlePossibleMetaViewportChange();
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 TabChild::Observe(nsISupports *aSubject,
                   const char *aTopic,
                   const PRUnichar *aData)
 {
-  if (!strcmp(aTopic, "cancel-default-pan-zoom")) {
+  if (!strcmp(aTopic, CANCEL_DEFAULT_PAN_ZOOM)) {
     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
     nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
     if (tabChild == this) {
       mRemoteFrame->CancelDefaultPanZoom();
     }
-  } else if (!strcmp(aTopic, "browser-zoom-to-rect")) {
+  } else if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
     nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
     if (tabChild == this) {
       gfxRect rect;
       sscanf(NS_ConvertUTF16toUTF8(aData).get(),
              "{\"x\":%lf,\"y\":%lf,\"w\":%lf,\"h\":%lf}",
              &rect.x, &rect.y, &rect.width, &rect.height);
       SendZoomToRect(rect);
     }
+  } else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
+    if (IsAsyncPanZoomEnabled()) {
+      nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
+      nsCOMPtr<nsIDOMDocument> domDoc;
+      mWebNav->GetDocument(getter_AddRefs(domDoc));
+      nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
+
+      if (SameCOMIdentity(subject, doc)) {
+        nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
+
+        mContentDocumentIsDisplayed = true;
+
+        // Reset CSS viewport and zoom to default on new page, then calculate them
+        // properly using the actual metadata from the page.
+        SetCSSViewport(kDefaultViewportSize.width, kDefaultViewportSize.height);
+
+        // Calculate a really simple resolution that we probably won't be
+        // keeping, as well as putting the scroll offset back to the top-left of
+        // the page.
+        float resolution = float(mInnerSize.width) / float(kDefaultViewportSize.width);
+        mLastMetrics.mZoom.width = mLastMetrics.mZoom.height =
+          mLastMetrics.mResolution.width = mLastMetrics.mResolution.height =
+            resolution;
+        mLastMetrics.mScrollOffset = gfx::Point(0, 0);
+        utils->SetResolution(resolution, resolution);
+
+        HandlePossibleMetaViewportChange();
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TabChild::OnStateChange(nsIWebProgress* aWebProgress,
+                        nsIRequest* aRequest,
+                        uint32_t aStateFlags,
+                        nsresult aStatus)
+{
+  NS_NOTREACHED("not implemented in TabChild");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TabChild::OnProgressChange(nsIWebProgress* aWebProgress,
+                           nsIRequest* aRequest,
+                           int32_t aCurSelfProgress,
+                           int32_t aMaxSelfProgress,
+                           int32_t aCurTotalProgress,
+                           int32_t aMaxTotalProgress)
+{
+  NS_NOTREACHED("not implemented in TabChild");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TabChild::OnLocationChange(nsIWebProgress* aWebProgress,
+                           nsIRequest* aRequest,
+                           nsIURI *aLocation,
+                           uint32_t aFlags)
+{
+  if (!IsAsyncPanZoomEnabled()) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMWindow> window;
+  aWebProgress->GetDOMWindow(getter_AddRefs(window));
+  if (!window) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMDocument> progressDoc;
+  window->GetDocument(getter_AddRefs(progressDoc));
+  if (!progressDoc) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMDocument> domDoc;
+  mWebNav->GetDocument(getter_AddRefs(domDoc));
+  if (!domDoc || !SameCOMIdentity(domDoc, progressDoc)) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
+  if (!urifixup) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIURI> exposableURI;
+  urifixup->CreateExposableURI(aLocation, getter_AddRefs(exposableURI));
+  if (!exposableURI) {
+    return NS_OK;
+  }
+
+  if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
+    mContentDocumentIsDisplayed = false;
+  } else if (mLastURI != nullptr) {
+    bool exposableEqualsLast, exposableEqualsNew;
+    exposableURI->Equals(mLastURI.get(), &exposableEqualsLast);
+    exposableURI->Equals(aLocation, &exposableEqualsNew);
+    if (exposableEqualsLast && !exposableEqualsNew) {
+      mContentDocumentIsDisplayed = false;
+    }
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TabChild::OnStatusChange(nsIWebProgress* aWebProgress,
+                         nsIRequest* aRequest,
+                         nsresult aStatus,
+                         const PRUnichar* aMessage)
+{
+  NS_NOTREACHED("not implemented in TabChild");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TabChild::OnSecurityChange(nsIWebProgress* aWebProgress,
+                           nsIRequest* aRequest,
+                           uint32_t aState)
+{
+  NS_NOTREACHED("not implemented in TabChild");
+  return NS_OK;
+}
+
+void
+TabChild::SetCSSViewport(float aWidth, float aHeight)
+{
+  mOldViewportWidth = aWidth;
+
+  if (mContentDocumentIsDisplayed) {
+    nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
+    utils->SetCSSViewport(aWidth, aHeight);
+  }
+}
+
+void
+TabChild::HandlePossibleMetaViewportChange()
+{
+  if (!IsAsyncPanZoomEnabled()) {
+    return;
+  }
+
+  nsCOMPtr<nsIDOMDocument> domDoc;
+  mWebNav->GetDocument(getter_AddRefs(domDoc));
+  nsCOMPtr<nsIDocument> document(do_QueryInterface(domDoc));
+
+  nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
+
+  ViewportInfo viewportMetaData =
+    nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height);
+  SendUpdateZoomConstraints(viewportMetaData.allowZoom,
+                            viewportMetaData.minZoom,
+                            viewportMetaData.maxZoom);
+
+  float screenW = mInnerSize.width;
+  float screenH = mInnerSize.height;
+  float viewportW = viewportMetaData.width;
+  float viewportH = viewportMetaData.height;
+
+  // We're not being displayed in any way; don't bother doing anything because
+  // that will just confuse future adjustments.
+  if (!screenW || !screenH) {
+    return;
+  }
+
+  // Make sure the viewport height is not shorter than the window when the page
+  // is zoomed out to show its full width. Note that before we set the viewport
+  // width, the "full width" of the page isn't properly defined, so that's why
+  // we have to call SetCSSViewport twice - once to set the width, and the
+  // second time to figure out the height based on the layout at that width.
+  float oldBrowserWidth = mOldViewportWidth;
+  mLastMetrics.mViewport.width = viewportMetaData.width;
+  mLastMetrics.mViewport.height = viewportMetaData.height;
+  if (!oldBrowserWidth) {
+    oldBrowserWidth = kDefaultViewportSize.width;
+  }
+  SetCSSViewport(viewportW, viewportH);
+
+  // If this page has not been painted yet, then this must be getting run
+  // because a meta-viewport element was added (via the DOMMetaAdded handler).
+  // in this case, we should not do anything that forces a reflow (see bug
+  // 759678) such as requesting the page size or sending a viewport update. this
+  // code will get run again in the before-first-paint handler and that point we
+  // will run though all of it. the reason we even bother executing up to this
+  // point on the DOMMetaAdded handler is so that scripts that use
+  // window.innerWidth before they are painted have a correct value (bug
+  // 771575).
+  if (!mContentDocumentIsDisplayed) {
+    return;
+  }
+
+  float minScale = 1.0f;
+
+  nsCOMPtr<nsIDOMElement> htmlDOMElement = do_QueryInterface(document->GetHtmlElement());
+  nsCOMPtr<nsIDOMElement> bodyDOMElement = do_QueryInterface(document->GetBodyElement());
+
+  PRInt32 htmlWidth = 0, htmlHeight = 0;
+  if (htmlDOMElement) {
+    htmlDOMElement->GetScrollWidth(&htmlWidth);
+    htmlDOMElement->GetScrollHeight(&htmlHeight);
+  }
+  PRInt32 bodyWidth = 0, bodyHeight = 0;
+  if (bodyDOMElement) {
+    bodyDOMElement->GetScrollWidth(&bodyWidth);
+    bodyDOMElement->GetScrollHeight(&bodyHeight);
+  }
+
+  float pageWidth = NS_MAX(htmlWidth, bodyWidth);
+  float pageHeight = NS_MAX(htmlHeight, bodyHeight);
+
+  minScale = mInnerSize.width / pageWidth;
+  minScale = clamped((double)minScale, viewportMetaData.minZoom, viewportMetaData.maxZoom);
+
+  viewportH = NS_MAX(viewportH, screenH / minScale);
+  SetCSSViewport(viewportW, viewportH);
+
+  // This change to the zoom accounts for all types of changes I can conceive:
+  // 1. screen size changes, CSS viewport does not (pages with no meta viewport
+  //    or a fixed size viewport)
+  // 2. screen size changes, CSS viewport also does (pages with a device-width
+  //    viewport)
+  // 3. screen size remains constant, but CSS viewport changes (meta viewport
+  //    tag is added or removed)
+  // 4. neither screen size nor CSS viewport changes
+  //
+  // In all of these cases, we maintain how much actual content is visible
+  // within the screen width. Note that "actual content" may be different with
+  // respect to CSS pixels because of the CSS viewport size changing.
+  int32_t oldScreenWidth = mLastMetrics.mCompositionBounds.width;
+  if (!oldScreenWidth) {
+    oldScreenWidth = mInnerSize.width;
+  }
+  float zoomScale = (screenW * oldBrowserWidth) / (oldScreenWidth * viewportW);
+
+  float zoom = clamped(double(mLastMetrics.mZoom.width * zoomScale),
+                       viewportMetaData.minZoom, viewportMetaData.maxZoom);
+  utils->SetResolution(zoom, zoom);
+
+  FrameMetrics metrics(mLastMetrics);
+  metrics.mViewport = gfx::Rect(0.0f, 0.0f, viewportW, viewportH);
+  metrics.mScrollableRect = gfx::Rect(0.0f, 0.0f, pageWidth, pageHeight);
+  metrics.mCompositionBounds = nsIntRect(0, 0, mInnerSize.width, mInnerSize.height);
+  metrics.mZoom.width = metrics.mZoom.height =
+    metrics.mResolution.width = metrics.mResolution.height = zoom;
+  metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
+    // The page must have been refreshed in some way such as a new document or
+    // new CSS viewport, so we know that there's no velocity, acceleration, and
+    // we have no idea how long painting will take.
+    metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
+  // Force a repaint with these metrics. This, among other things, sets the
+  // displayport, so we start with async painting.
+  RecvUpdateFrame(metrics);
+}
+
 nsresult
 TabChild::Init()
 {
   nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
   if (!webBrowser) {
     NS_ERROR("Couldn't create a nsWebBrowser?");
     return NS_ERROR_FAILURE;
   }
@@ -233,16 +514,22 @@ TabChild::Init()
   if (webBrowserSetup) {
     webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH,
                                  true);
   } else {
     NS_WARNING("baseWindow doesn't QI to nsIWebBrowserSetup, skipping "
                "DNS prefetching enable step.");
   }
 
+  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWebNav);
+  MOZ_ASSERT(docShell);
+  nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
+  NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
+  webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION);
+
   return NS_OK;
 }
 
 void
 TabChild::SetAppBrowserConfig(bool aIsBrowserElement, uint32_t aAppId)
 {
     mIsBrowserElement = aIsBrowserElement;
     mAppId = aAppId;
@@ -261,18 +548,21 @@ TabChild::SetAppBrowserConfig(bool aIsBr
 NS_INTERFACE_MAP_BEGIN(TabChild)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
+  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
   NS_INTERFACE_MAP_ENTRY(nsITabChild)
   NS_INTERFACE_MAP_ENTRY(nsIDialogCreator)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsSupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(TabChild)
 NS_IMPL_RELEASE(TabChild)
 
 NS_IMETHODIMP
 TabChild::SetStatus(uint32_t aStatusType, const PRUnichar* aStatus)
@@ -794,23 +1084,26 @@ TabChild::RecvUpdateDimensions(const nsR
         return true;
     }
 
     mOuterRect.x = rect.x;
     mOuterRect.y = rect.y;
     mOuterRect.width = rect.width;
     mOuterRect.height = rect.height;
 
+    mInnerSize = size;
     mWidget->Resize(0, 0, size.width, size.height,
                     true);
 
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mWebNav);
     baseWin->SetPositionAndSize(0, 0, size.width, size.height,
                                 true);
 
+    HandlePossibleMetaViewportChange();
+
     return true;
 }
 
 void
 TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
                                         const nsACString& aJSONData)
 {
     JSAutoRequest ar(mCx);
@@ -837,43 +1130,73 @@ TabChild::DispatchMessageManagerMessage(
 
 bool
 TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
 {
     if (!mCx || !mTabChildGlobal) {
         return true;
     }
 
+    // The BrowserElementScrolling helper must know about these updated metrics
+    // for other functions it performs, such as double tap handling.
     nsCString data;
-    data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mViewportScrollOffset.x));
-    data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mViewportScrollOffset.y));
+    data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
+    data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
     // We don't treat the x and y scales any differently for this
     // semi-platform-specific code.
-    data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mResolution.width);
+    data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mZoom.width);
     data += nsPrintfCString(", \"displayPort\" : ");
-        data += nsPrintfCString("{ \"left\" : %d", aFrameMetrics.mDisplayPort.X());
-        data += nsPrintfCString(", \"top\" : %d", aFrameMetrics.mDisplayPort.Y());
-        data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mDisplayPort.Width());
-        data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mDisplayPort.Height());
+        data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mDisplayPort.x);
+        data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mDisplayPort.y);
+        data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mDisplayPort.width);
+        data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mDisplayPort.height);
         data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
         data += nsPrintfCString(" }");
-    data += nsPrintfCString(", \"screenSize\" : ");
-        data += nsPrintfCString("{ \"width\" : %d", aFrameMetrics.mViewport.width);
-        data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mViewport.height);
+    data += nsPrintfCString(", \"compositionBounds\" : ");
+        data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
+        data += nsPrintfCString(", \"y\" : %d", aFrameMetrics.mCompositionBounds.y);
+        data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mCompositionBounds.width);
+        data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mCompositionBounds.height);
         data += nsPrintfCString(" }");
     data += nsPrintfCString(", \"cssPageRect\" : ");
-        data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mCSSContentRect.x);
-        data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mCSSContentRect.y);
-        data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mCSSContentRect.width);
-        data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mCSSContentRect.height);
+        data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mScrollableRect.x);
+        data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mScrollableRect.y);
+        data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mScrollableRect.width);
+        data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mScrollableRect.height);
         data += nsPrintfCString(" }");
     data += nsPrintfCString(" }");
 
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
 
+    nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
+    nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mWebNav);
+
+    utils->SetScrollPositionClampingScrollPortSize(
+      aFrameMetrics.mCompositionBounds.width / aFrameMetrics.mZoom.width,
+      aFrameMetrics.mCompositionBounds.height / aFrameMetrics.mZoom.width);
+    window->ScrollTo(aFrameMetrics.mScrollOffset.x,
+                     aFrameMetrics.mScrollOffset.y);
+    utils->SetResolution(aFrameMetrics.mResolution.width,
+                         aFrameMetrics.mResolution.width);
+
+    nsCOMPtr<nsIDOMDocument> domDoc;
+    nsCOMPtr<nsIDOMElement> docElement;
+    mWebNav->GetDocument(getter_AddRefs(domDoc));
+    if (domDoc) {
+      domDoc->GetDocumentElement(getter_AddRefs(docElement));
+      if (docElement) {
+        utils->SetDisplayPortForElement(
+          aFrameMetrics.mDisplayPort.x, aFrameMetrics.mDisplayPort.y,
+          aFrameMetrics.mDisplayPort.width, aFrameMetrics.mDisplayPort.height,
+          docElement);
+      }
+    }
+
+    mLastMetrics = aFrameMetrics;
+
     return true;
 }
 
 bool
 TabChild::RecvHandleDoubleTap(const nsIntPoint& aPoint)
 {
     if (!mCx || !mTabChildGlobal) {
         return true;
@@ -921,18 +1244,17 @@ bool
 TabChild::RecvMouseEvent(const nsString& aType,
                          const float&    aX,
                          const float&    aY,
                          const int32_t&  aButton,
                          const int32_t&  aClickCount,
                          const int32_t&  aModifiers,
                          const bool&     aIgnoreRootScrollFrame)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
-  nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
+  nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
   NS_ENSURE_TRUE(utils, true);
   utils->SendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers,
                         aIgnoreRootScrollFrame, 0, 0);
   return true;
 }
 
 bool
 TabChild::RecvRealMouseEvent(const nsMouseEvent& event)
@@ -1023,18 +1345,17 @@ TabChild::RecvRealKeyEvent(const nsKeyEv
 
 bool
 TabChild::RecvKeyEvent(const nsString& aType,
                        const int32_t& aKeyCode,
                        const int32_t& aCharCode,
                        const int32_t& aModifiers,
                        const bool& aPreventDefault)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
-  nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
+  nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
   NS_ENSURE_TRUE(utils, true);
   bool ignored = false;
   utils->SendKeyEvent(aType, aKeyCode, aCharCode,
                       aModifiers, aPreventDefault, &ignored);
   return true;
 }
 
 bool
@@ -1274,16 +1595,23 @@ TabChild::RecvDestroy()
 {
   if (mTabChildGlobal) {
     // Let the frame scripts know the child is being closed
     nsContentUtils::AddScriptRunner(
       new UnloadScriptEvent(this, mTabChildGlobal)
     );
   }
 
+  nsCOMPtr<nsIObserverService> observerService =
+    do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
+
+  observerService->RemoveObserver(this, CANCEL_DEFAULT_PAN_ZOOM);
+  observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
+  observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
+
   // XXX what other code in ~TabChild() should we be running here?
   DestroyWindow();
 
   return Send__delete__(this);
 }
 
 PRenderFrameChild*
 TabChild::AllocPRenderFrame(ScrollingBehavior* aScrolling,
@@ -1312,24 +1640,26 @@ TabChild::InitTabChildGlobal(FrameScript
     NS_ENSURE_TRUE(chromeHandler, false);
 
     nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
     NS_ENSURE_TRUE(scope, false);
 
     mTabChildGlobal = scope;
 
     nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIDOMEventTarget*, scope);
-  
+
     NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false); 
 
     scope->Init();
 
     nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
     NS_ENSURE_TRUE(root, false);
     root->SetParentTarget(scope);
+
+    chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
   }
 
   if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
     mTriedBrowserInit = true;
     // Initialize the child side of the browser element machinery,
     // if appropriate.
     if (mIsBrowserElement || mAppId != nsIScriptSecurityManager::NO_APP_ID) {
       RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT);
@@ -1384,20 +1714,23 @@ TabChild::InitRenderingState()
 
     mRemoteFrame = remoteFrame;
 
     nsCOMPtr<nsIObserverService> observerService =
         do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
 
     if (observerService) {
         observerService->AddObserver(this,
-                                     "cancel-default-pan-zoom",
+                                     CANCEL_DEFAULT_PAN_ZOOM,
                                      false);
         observerService->AddObserver(this,
-                                     "browser-zoom-to-rect",
+                                     BROWSER_ZOOM_TO_RECT,
+                                     false);
+        observerService->AddObserver(this,
+                                     BEFORE_FIRST_PAINT,
                                      false);
     }
 
     return true;
 }
 
 void
 TabChild::SetBackgroundColor(const nscolor& aColor)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -31,19 +31,21 @@
 #include "nsIDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsNetUtil.h"
 #include "nsFrameMessageManager.h"
 #include "nsIScriptContext.h"
+#include "nsIWebProgressListener.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDialogCreator.h"
 #include "nsIDialogParamBlock.h"
+#include "nsIDOMWindowUtils.h"
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsPIDOMWindow.h"
 #include "nsWeakReference.h"
 #include "nsITabChild.h"
 #include "mozilla/Attributes.h"
@@ -136,16 +138,18 @@ protected:
 
 class TabChild : public PBrowserChild,
                  public nsFrameScriptExecutor,
                  public nsIWebBrowserChrome2,
                  public nsIEmbeddingSiteWindow,
                  public nsIWebBrowserChromeFocus,
                  public nsIInterfaceRequestor,
                  public nsIWindowProvider,
+                 public nsIDOMEventListener,
+                 public nsIWebProgressListener,
                  public nsSupportsWeakReference,
                  public nsIDialogCreator,
                  public nsITabChild,
                  public nsIObserver,
                  public mozilla::dom::ipc::MessageManagerCallback
 {
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@@ -170,16 +174,18 @@ public:
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSIWINDOWPROVIDER
+    NS_DECL_NSIDOMEVENTLISTENER
+    NS_DECL_NSIWEBPROGRESSLISTENER
     NS_DECL_NSIDIALOGCREATOR
     NS_DECL_NSITABCHILD
     NS_DECL_NSIOBSERVER
 
     /**
      * MessageManagerCallback methods that we override.
      */
     virtual bool DoSendSyncMessage(const nsAString& aMessage,
@@ -323,16 +329,26 @@ private:
     bool InitTabChildGlobal(FrameScriptLoading aScriptLoading = DEFAULT_LOAD_SCRIPTS);
     bool InitRenderingState();
     void DestroyWindow();
     void SetProcessNameToAppName();
 
     // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
     void DoFakeShow();
 
+    // Wrapper for nsIDOMWindowUtils.setCSSViewport(). This updates some state
+    // variables local to this class before setting it.
+    void SetCSSViewport(float aX, float aY);
+
+    // Recalculates the display state, including the CSS viewport. This should
+    // be called whenever we believe the meta viewport data on a document may
+    // have changed. If it didn't change, this function doesn't do anything.
+    // However, it should not be called all the time as it is fairly expensive.
+    void HandlePossibleMetaViewportChange();
+
     // Wraps up a JSON object as a structured clone and sends it to the browser
     // chrome script.
     //
     // XXX/bug 780335: Do the work the browser chrome script does in C++ instead
     // so we don't need things like this.
     void DispatchMessageManagerMessage(const nsAString& aMessageName,
                                        const nsACString& aJSONData);
 
@@ -342,28 +358,40 @@ private:
     nsresult
     BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
                               nsIURI* aURI,
                               const nsAString& aName,
                               const nsACString& aFeatures,
                               bool* aWindowIsNew,
                               nsIDOMWindow** aReturn);
 
+    nsIDOMWindowUtils* GetDOMWindowUtils()
+    {
+        nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
+        nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
+        return utils;
+    }
+
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
+    nsCOMPtr<nsIURI> mLastURI;
+    FrameMetrics mLastMetrics;
     RenderFrameChild* mRemoteFrame;
     nsRefPtr<TabChildGlobal> mTabChildGlobal;
     uint32_t mChromeFlags;
     nsIntRect mOuterRect;
+    nsIntSize mInnerSize;
+    float mOldViewportWidth;
     nscolor mLastBackgroundColor;
     ScrollingBehavior mScrolling;
     uint32_t mAppId;
     bool mDidFakeShow;
     bool mIsBrowserElement;
     bool mNotified;
+    bool mContentDocumentIsDisplayed;
     bool mTriedBrowserInit;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
 GetTabChildFrom(nsIDocShell* aDocShell)
 {
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -78,16 +78,17 @@ TabParent::TabParent(mozIApplication* aA
   , mApp(aApp)
   , mIMESelectionAnchor(0)
   , mIMESelectionFocus(0)
   , mIMEComposing(false)
   , mIMECompositionEnding(false)
   , mIMECompositionStart(0)
   , mIMESeqno(0)
   , mEventCaptureDepth(0)
+  , mDimensions(0, 0)
   , mDPI(0)
   , mIsBrowserElement(aIsBrowserElement)
   , mShown(false)
 {
 }
 
 TabParent::~TabParent()
 {
@@ -224,26 +225,28 @@ TabParent::LoadURL(nsIURI* aURI)
     unused << SendLoadURL(spec);
 }
 
 void
 TabParent::Show(const nsIntSize& size)
 {
     // sigh
     mShown = true;
+    mDimensions = size;
     unused << SendShow(size);
 }
 
 void
 TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
 {
   unused << SendUpdateDimensions(rect, size);
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->NotifyDimensionsChanged(size.width, size.height);
   }
+  mDimensions = size;
 }
 
 void
 TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   unused << SendUpdateFrame(aFrameMetrics);
 }
 
@@ -1168,25 +1171,51 @@ TabParent::RecvBrowserFrameOpenWindow(PB
 {
   *aOutWindowOpened =
     BrowserElementParent::OpenWindowOOP(static_cast<TabParent*>(aOpener),
                                         this, aURL, aName, aFeatures);
   return true;
 }
 
 bool
+TabParent::RecvPRenderFrameConstructor(PRenderFrameParent* actor,
+                                       ScrollingBehavior* scrolling,
+                                       LayersBackend* backend,
+                                       int32_t* maxTextureSize,
+                                       uint64_t* layersId)
+{
+  RenderFrameParent* rfp = GetRenderFrame();
+  if (mDimensions != nsIntSize() && rfp) {
+    rfp->NotifyDimensionsChanged(mDimensions.width, mDimensions.height);
+  }
+
+  return true;
+}
+
+bool
 TabParent::RecvZoomToRect(const gfxRect& aRect)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->ZoomToRect(aRect);
   }
   return true;
 }
 
 bool
+TabParent::RecvUpdateZoomConstraints(const bool& aAllowZoom,
+                                     const float& aMinZoom,
+                                     const float& aMaxZoom)
+{
+  if (RenderFrameParent* rfp = GetRenderFrame()) {
+    rfp->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
+  }
+  return true;
+}
+
+bool
 TabParent::RecvContentReceivedTouch(const bool& aPreventDefault)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->ContentReceivedTouch(aPreventDefault);
   }
   return true;
 }
 
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -89,16 +89,21 @@ public:
      * capturer.
      */
     bool TryCapture(const nsGUIEvent& aEvent);
 
     void Destroy();
 
     virtual bool RecvMoveFocus(const bool& aForward);
     virtual bool RecvEvent(const RemoteDOMEvent& aEvent);
+    virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* actor,
+                                             ScrollingBehavior* scrolling,
+                                             LayersBackend* backend,
+                                             int32_t* maxTextureSize,
+                                             uint64_t* layersId);
     virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                             const nsString& aURL,
                                             const nsString& aName,
                                             const nsString& aFeatures,
                                             bool* aOutWindowOpened);
     virtual bool AnswerCreateWindow(PBrowserParent** retval);
     virtual bool RecvSyncMessage(const nsString& aMessage,
                                  const ClonedMessageData& aData,
@@ -126,16 +131,19 @@ public:
                                      const nsString& aActionHint,
                                      const int32_t& aCause,
                                      const int32_t& aFocusChange);
     virtual bool RecvSetCursor(const uint32_t& aValue);
     virtual bool RecvSetBackgroundColor(const nscolor& aValue);
     virtual bool RecvGetDPI(float* aValue);
     virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
     virtual bool RecvZoomToRect(const gfxRect& aRect);
+    virtual bool RecvUpdateZoomConstraints(const bool& aAllowZoom,
+                                           const float& aMinZoom,
+                                           const float& aMaxZoom);
     virtual bool RecvContentReceivedTouch(const bool& aPreventDefault);
     virtual PContentDialogParent* AllocPContentDialog(const uint32_t& aType,
                                                       const nsCString& aName,
                                                       const nsCString& aFeatures,
                                                       const InfallibleTArray<int>& aIntParams,
                                                       const InfallibleTArray<nsString>& aStringParams);
     virtual bool DeallocPContentDialog(PContentDialogParent* aDialog)
     {
@@ -264,16 +272,17 @@ protected:
     // Compositions in almost all cases are small enough for nsAutoString
     nsAutoString mIMECompositionText;
     uint32_t mIMECompositionStart;
     uint32_t mIMESeqno;
 
     // The number of event series we're currently capturing.
     int32_t mEventCaptureDepth;
 
+    nsIntSize mDimensions;
     float mDPI;
     bool mIsBrowserElement;
     bool mShown;
 
 private:
     already_AddRefed<nsFrameLoader> GetFrameLoader() const;
     already_AddRefed<nsIWidget> GetWidget() const;
     layout::RenderFrameParent* GetRenderFrame();
--- a/dom/network/interfaces/nsIMobileConnectionProvider.idl
+++ b/dom/network/interfaces/nsIMobileConnectionProvider.idl
@@ -9,17 +9,17 @@ interface nsIDOMMozMobileConnectionInfo;
 interface nsIDOMMozMobileNetworkInfo;
 interface nsIDOMDOMRequest;
 interface nsIDOMWindow;
 
 /**
  * XPCOM component (in the content process) that provides the mobile
  * network information.
  */
-[scriptable, uuid(63787ba1-5091-450b-8810-d321a8b4f77a)]
+[scriptable, uuid(bc1a82aa-2a1f-4a27-a5e7-614d06b72e0a)]
 interface nsIMobileConnectionProvider : nsISupports
 {
   readonly attribute DOMString cardState;
   readonly attribute nsIDOMMozMobileICCInfo iccInfo;
   readonly attribute nsIDOMMozMobileConnectionInfo voiceConnectionInfo;
   readonly attribute nsIDOMMozMobileConnectionInfo dataConnectionInfo;
   readonly attribute DOMString networkSelectionMode;
 
@@ -35,9 +35,11 @@ interface nsIMobileConnectionProvider : 
   nsIDOMDOMRequest cancelUSSD(in nsIDOMWindow window);
 
   void sendStkResponse(in nsIDOMWindow window,
                        in jsval        command,
                        in jsval        response);
   void sendStkMenuSelection(in nsIDOMWindow   window,
                             in unsigned short itemIdentifier,
                             in boolean        helpRequested);
+  void sendStkEventDownload(in nsIDOMWindow window,
+                            in jsval        event);
 };
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -27,34 +27,37 @@ using namespace mozilla::hal;
 using namespace mozilla;
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AudioManager" , ## args) 
 
 #define HEADPHONES_STATUS_CHANGED "headphones-status-changed"
 #define HEADPHONES_STATUS_ON      NS_LITERAL_STRING("on").get()
 #define HEADPHONES_STATUS_OFF     NS_LITERAL_STRING("off").get()
 #define HEADPHONES_STATUS_UNKNOWN NS_LITERAL_STRING("unknown").get()
+#define BLUETOOTH_SCO_STATUS_CHANGED "bluetooth-sco-status-changed"
 
 // A bitwise variable for recording what kind of headset is attached.
 static int sHeadsetState;
+static const char* sDeviceAddress;
+static int kBtSampleRate = 8000;
 
 static bool
 IsFmRadioAudioOn()
 {
   if (static_cast<
       audio_policy_dev_state_t (*) (audio_devices_t, const char *)
       >(AudioSystem::getDeviceConnectionState)) {
     return AudioSystem::getDeviceConnectionState(AUDIO_DEVICE_OUT_FM, "") == 
            AUDIO_POLICY_DEVICE_STATE_AVAILABLE ? true : false;
   } else {
     return false;
   }
 }
 
-NS_IMPL_ISUPPORTS1(AudioManager, nsIAudioManager)
+NS_IMPL_ISUPPORTS2(AudioManager, nsIAudioManager, nsIObserver)
 
 static AudioSystem::audio_devices
 GetRoutingMode(int aType) {
   if (aType == nsIAudioManager::FORCE_SPEAKER) {
     return AudioSystem::DEVICE_OUT_SPEAKER;
   } else if (aType == nsIAudioManager::FORCE_HEADPHONES) {
     return AudioSystem::DEVICE_OUT_WIRED_HEADSET;
   } else if (aType == nsIAudioManager::FORCE_BT_SCO) {
@@ -72,16 +75,20 @@ InternalSetAudioRoutesICS(SwitchState aS
   if (aState == SWITCH_STATE_HEADSET) {
     AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADSET,
                                           AUDIO_POLICY_DEVICE_STATE_AVAILABLE, "");
     sHeadsetState |= AUDIO_DEVICE_OUT_WIRED_HEADSET;
   } else if (aState == SWITCH_STATE_HEADPHONE) {
     AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
                                           AUDIO_POLICY_DEVICE_STATE_AVAILABLE, "");
     sHeadsetState |= AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+  } else if (aState == SWITCH_STATE_BLUETOOTH_SCO) {
+    AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+                                          AUDIO_POLICY_DEVICE_STATE_AVAILABLE, sDeviceAddress);
+    sHeadsetState |= AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
   } else if (aState == SWITCH_STATE_OFF) {
     AudioSystem::setDeviceConnectionState(static_cast<audio_devices_t>(sHeadsetState),
                                           AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "");
     sHeadsetState = 0;
   }
 
   // The audio volume is not consistent when we plug and unplug the headset.
   // Set the fm volume again here.
@@ -117,16 +124,33 @@ InternalSetAudioRoutes(SwitchState aStat
     InternalSetAudioRoutesICS(aState);
   } else if (static_cast<
     audio_io_handle_t (*)(AudioSystem::stream_type, uint32_t, uint32_t, uint32_t, AudioSystem::output_flags)
     >(AudioSystem::getOutput)) {
     InternalSetAudioRoutesGB(aState);
   }
 }
 
+nsresult
+AudioManager::Observe(nsISupports* aSubject,
+                      const char* aTopic,
+                      const PRUnichar* aData)
+{
+  if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED)) {
+    String8 cmd;
+    cmd.appendFormat("bt_samplerate=%d", kBtSampleRate);
+    AudioSystem::setParameters(0, cmd);
+
+    sDeviceAddress = NS_ConvertUTF16toUTF8(nsDependentString(aData)).get();
+    InternalSetAudioRoutes(SwitchState::SWITCH_STATE_BLUETOOTH_SCO);
+    return NS_OK;
+  }
+  return NS_ERROR_UNEXPECTED;
+}
+
 static void
 NotifyHeadphonesStatus(SwitchState aState)
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     if (aState == SWITCH_STATE_ON) {
       obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_ON);
     } else if (aState == SWITCH_STATE_OFF) {
@@ -148,20 +172,30 @@ public:
 
 AudioManager::AudioManager() : mPhoneState(PHONE_STATE_CURRENT),
                  mObserver(new HeadphoneSwitchObserver())
 {
   RegisterSwitchObserver(SWITCH_HEADPHONES, mObserver);
 
   InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
   NotifyHeadphonesStatus(GetCurrentSwitchState(SWITCH_HEADPHONES));
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_SCO_STATUS_CHANGED, false))) {
+    NS_WARNING("Failed to add bluetooth-sco-status-changed oberver!");
+  }
 }
 
 AudioManager::~AudioManager() {
   UnregisterSwitchObserver(SWITCH_HEADPHONES, mObserver);
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_SCO_STATUS_CHANGED))) {
+    NS_WARNING("Failed to add bluetooth-sco-status-changed oberver!");
+  }
 }
 
 NS_IMETHODIMP
 AudioManager::GetMicrophoneMuted(bool* aMicrophoneMuted)
 {
   if (AudioSystem::isMicrophoneMuted(aMicrophoneMuted)) {
     return NS_ERROR_FAILURE;
   }
--- a/dom/system/gonk/AudioManager.h
+++ b/dom/system/gonk/AudioManager.h
@@ -14,16 +14,17 @@
  */
 
 #ifndef mozilla_dom_system_b2g_audiomanager_h__
 #define mozilla_dom_system_b2g_audiomanager_h__
 
 #include "mozilla/Observer.h"
 #include "nsAutoPtr.h"
 #include "nsIAudioManager.h"
+#include "nsIObserver.h"
 
 // {b2b51423-502d-4d77-89b3-7786b562b084}
 #define NS_AUDIOMANAGER_CID {0x94f6fd70, 0x7615, 0x4af9, \
       {0x89, 0x10, 0xf9, 0x3c, 0x55, 0xe6, 0x62, 0xec}}
 #define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
 
 
 namespace mozilla {
@@ -31,20 +32,22 @@ namespace hal {
 class SwitchEvent;
 typedef Observer<SwitchEvent> SwitchObserver;
 } // namespace hal
 
 namespace dom {
 namespace gonk {
 
 class AudioManager : public nsIAudioManager
+                   , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAUDIOMANAGER
+  NS_DECL_NSIOBSERVER
 
   AudioManager();
   ~AudioManager();
 
 protected:
   int32_t mPhoneState;
 
 private:
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -448,16 +448,25 @@ RILContentHelper.prototype = {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
     cpmm.sendAsyncMessage("RIL:SendStkMenuSelection", {itemIdentifier: itemIdentifier,
                                                        helpRequested: helpRequested});
   },
 
+  sendStkEventDownload: function sendStkEventDownload(window,
+                                                      event) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {event: event});
+  },
+
   _telephonyCallbacks: null,
   _voicemailCallbacks: null,
   _enumerateTelephonyCallbacks: null,
 
   voicemailStatus: null,
   voicemailNumber: null,
   voicemailDisplayName: null,
 
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -68,16 +68,17 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES
   "RIL:SelectNetworkAuto",
   "RIL:GetCardLock",
   "RIL:UnlockCardLock",
   "RIL:SetCardLock",
   "RIL:SendUSSD",
   "RIL:CancelUSSD",
   "RIL:SendStkResponse",
   "RIL:SendStkMenuSelection",
+  "RIL:SendStkEventDownload",
 ];
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
                                    "@mozilla.org/sms/smsservice;1",
                                    "nsISmsService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsRequestManager",
                                    "@mozilla.org/sms/smsrequestmanager;1",
@@ -379,16 +380,19 @@ RadioInterfaceLayer.prototype = {
         this.cancelUSSD(msg.json);
         break;
       case "RIL:SendStkResponse":
         this.sendStkResponse(msg.json);
         break;
       case "RIL:SendStkMenuSelection":
         this.sendStkMenuSelection(msg.json);
         break;
+      case "RIL:SendStkEventDownload":
+        this.sendStkEventDownload(msg.json);
+        break;
     }
   },
 
   onerror: function onerror(event) {
     debug("Got an error: " + event.filename + ":" +
           event.lineno + ": " + event.message + "\n");
     event.preventDefault();
   },
@@ -1525,16 +1529,21 @@ RadioInterfaceLayer.prototype = {
     this.worker.postMessage(message);
   },
 
   sendStkMenuSelection: function sendStkMenuSelection(message) {
     message.rilMessageType = "sendStkMenuSelection";
     this.worker.postMessage(message);
   },
 
+  sendStkEventDownload: function sendStkEventDownload(message) {
+    message.rilMessageType = "sendStkEventDownload";
+    this.worker.postMessage(message);
+  },
+
   get microphoneMuted() {
     return gAudioManager.microphoneMuted;
   },
   set microphoneMuted(value) {
     if (value == this.microphoneMuted) {
       return;
     }
     gAudioManager.microphoneMuted = value;
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -532,44 +532,51 @@ const COMPREHENSIONTLV_FLAG_CR = 0x80;  
 const COMPREHENSIONTLV_TAG_COMMAND_DETAILS = 0x01;
 const COMPREHENSIONTLV_TAG_DEVICE_ID = 0x02;
 const COMPREHENSIONTLV_TAG_RESULT = 0x03;
 const COMPREHENSIONTLV_TAG_DURATION = 0x04;
 const COMPREHENSIONTLV_TAG_ALPHA_ID = 0x05;
 const COMPREHENSIONTLV_TAG_ADDRESS = 0x06;
 const COMPREHENSIONTLV_TAG_SMS_TPDU = 0x0b;
 const COMPREHENSIONTLV_TAG_TEXT_STRING = 0x0d;
+const COMPREHENSIONTLV_TAG_TONE = 0x0e;
 const COMPREHENSIONTLV_TAG_ITEM = 0x0f;
 const COMPREHENSIONTLV_TAG_ITEM_ID = 0x10;
 const COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11;
+const COMPREHENSIONTLV_TAG_FILE_LIST = 0x12;
+const COMPREHENSIONTLV_TAG_LOCATION_INFO = 0x13;
 const COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15;
 const COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17;
+const COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b;
 const COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19;
 const COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
 const COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
 const COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE = 0x2b;
 const COMPREHENSIONTLV_TAG_URL = 0x31;
 
 // Device identifiers, see TS 11.14, clause 12.7
 const STK_DEVICE_ID_KEYPAD = 0x01;
 const STK_DEVICE_ID_DISPLAY = 0x02;
 const STK_DEVICE_ID_EARPIECE = 0x03;
 const STK_DEVICE_ID_SIM = 0x81;
 const STK_DEVICE_ID_ME = 0x82;
 const STK_DEVICE_ID_NETWORK = 0x83;
 
 // STK Proactive commands.
 const STK_CMD_REFRESH = 0x01;
+const STK_CMD_POLL_INTERVAL = 0x03;
+const STK_CMD_POLL_OFF = 0x04;
 const STK_CMD_SET_UP_EVENT_LIST = 0x05;
 const STK_CMD_SET_UP_CALL = 0x10;
 const STK_CMD_SEND_SS = 0x11;
 const STK_CMD_SEND_USSD = 0x12;
 const STK_CMD_SEND_SMS = 0x13;
 const STK_CMD_SEND_DTMF = 0x14;
 const STK_CMD_LAUNCH_BROWSER = 0x15;
+const STK_CMD_PLAY_TONE = 0x20;
 const STK_CMD_DISPLAY_TEXT = 0x21;
 const STK_CMD_GET_INKEY = 0x22;
 const STK_CMD_GET_INPUT = 0x23;
 const STK_CMD_SELECT_ITEM = 0x24;
 const STK_CMD_SET_UP_MENU = 0x25;
 const STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28;
 
 // STK Result code.
@@ -720,16 +727,46 @@ const STK_EVENT_TYPE_BROWSER_TERMINATION
 const STK_EVENT_TYPE_DATA_AVAILABLE = 0x09;
 const STK_EVENT_TYPE_CHANNEL_STATUS = 0x0a;
 const STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED = 0x0b;
 const STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED = 0x0c;
 const STK_EVENT_TYPE_LOCAL_CONNECTION = 0x0d;
 const STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e;
 const STK_EVENT_TYPE_BROWSING_STATUS = 0x0f;
 
+// STK Service state of Location Status.
+const STK_SERVICE_STATE_NORMAL      = 0x00;
+const STK_SERVICE_STATE_LIMITED     = 0x01;
+const STK_SERVICE_STATE_UNAVAILABLE = 0x02;
+
+// Refresh mode.
+const STK_REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE = 0x00;
+const STK_REFRESH_FILE_CHANGE = 0x01;
+const STK_REFRESH_NAA_INIT_AND_FILE_CHANGE = 0x02;
+const STK_REFRESH_NAA_INIT = 0x03;
+const STK_REFRESH_UICC_RESET = 0x04;
+
+// Tone type.
+const STK_TONE_TYPE_DIAL_TONE                = 0x01;
+const STK_TONE_TYPE_CALLED_SUBSCRIBER_BUSY   = 0x02;
+const STK_TONE_TYPE_CONGESTION               = 0x03;
+const STK_TONE_TYPE_RADIO_PATH_ACK           = 0x04;
+const STK_TONE_TYPE_RADIO_PATH_NOT_AVAILABLE = 0x05;
+const STK_TONE_TYPE_ERROR                    = 0x06;
+const STK_TONE_TYPE_CALL_WAITING_TONE        = 0x07;
+const STK_TONE_TYPE_RINGING_TONE             = 0x08;
+const STK_TONE_TYPE_GENERAL_BEEP             = 0x10;
+const STK_TONE_TYPE_POSITIVE_ACK_TONE        = 0x11;
+const STK_TONE_TYPE_NEGATIVE_ACK_TONE        = 0x12;
+
+// Time unit.
+const STK_TIME_UNIT_MINUTE       = 0x00;
+const STK_TIME_UNIT_SECOND       = 0x01;
+const STK_TIME_UNIT_TENTH_SECOND = 0x02;
+
 /**
  * (U)SIM Services.
  *
  * @see 3GPP TS 51.011 10.3.7 (SIM) and 3GPP TS 31.102 4.2.8 (USIM).
  */
 const GECKO_ICC_SERVICES = {
   sim: {
     ADN: 2,
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -46,16 +46,26 @@ let DEBUG = DEBUG_WORKER;
 const INT32_MAX   = 2147483647;
 const UINT8_SIZE  = 1;
 const UINT16_SIZE = 2;
 const UINT32_SIZE = 4;
 const PARCEL_SIZE_SIZE = UINT32_SIZE;
 
 const PDU_HEX_OCTET_SIZE = 4;
 
+const TLV_COMMAND_DETAILS_SIZE = 5;
+const TLV_DEVICE_ID_SIZE = 4;
+const TLV_RESULT_SIZE = 3;
+const TLV_ITEM_ID_SIZE = 3;
+const TLV_HELP_REQUESTED_SIZE = 2;
+const TLV_EVENT_LIST_SIZE = 3;
+const TLV_LOCATION_STATUS_SIZE = 3;
+const TLV_LOCATION_INFO_GSM_SIZE = 9;
+const TLV_LOCATION_INFO_UMTS_SIZE = 11;
+
 const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
 
 let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = libcutils.property_get("ro.moz.ril.callstate_extra_int");
 // This may change at runtime since in RIL v6 and later, we get the version
 // number via the UNSOLICITED_RIL_CONNECTED parcel.
 let RILQUIRKS_V5_LEGACY = libcutils.property_get("ro.moz.ril.v5_legacy");
 let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = libcutils.property_get("ro.moz.ril.dial_emergency_call");
 let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = libcutils.property_get("ro.moz.ril.emergency_by_default");
@@ -2252,20 +2262,20 @@ let RIL = {
           textLen = bits * 7 / 8 + (bits % 8 ? 1 : 0);
         } else {
           textLen = response.input.length;
         }
       }
     }
 
     // 1 octets = 2 chars.
-    let size = (5 + /* Size of Command Details TLV */
-                4 + /* Size of Device Identifier TLV */
-                3 + /* Size of Result */
-                (response.itemIdentifier ? 3 : 0) +
+    let size = (TLV_COMMAND_DETAILS_SIZE +
+                TLV_DEVICE_ID_SIZE +
+                TLV_RESULT_SIZE +
+