Merge m-c to inbound a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 13 Oct 2014 19:02:56 -0700
changeset 210276 3e08f81eed80e0152bec5050efc79ea66fa96d25
parent 210275 809b3ec41a5dbdcae1358b4be1d202203b548f29 (current diff)
parent 210208 54217864bae9ce772dabcb68d9a9cb0654431d34 (diff)
child 210277 e0c4c804b279197984fb2016ca20ba61a26aadfc
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone36.0a1
Merge m-c to inbound a=merge
browser/components/sessionstore/RevivableWindows.jsm
browser/components/sessionstore/test/browser_revive_windows.js
--- a/.hgtags
+++ b/.hgtags
@@ -99,8 +99,9 @@ 2520866d58740851d862c7c59246a4e3f8b4a176
 05025f4889a0bf4dc99ce0c244c750adc002f015 FIREFOX_AURORA_27_BASE
 9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
 ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE
 83c9853e136451474dfa6d1aaa60a7fca7d2d83a FIREFOX_AURORA_30_BASE
 cfde3603b0206e119abea76fdd6e134b634348f1 FIREFOX_AURORA_31_BASE
 16f3cac5e8fe471e12f76d6a94a477b14e78df7c FIREFOX_AURORA_32_BASE
 dc23164ba2a289a8b22902e30990c77d9677c214 FIREFOX_AURORA_33_BASE
 c360f3d1c00d73b0c1fb0a2c0da525cb55e58b83 FIREFOX_AURORA_34_BASE
+cec1a116c4f9a3e887d52e9a26e8bbec200fe162 FIREFOX_AURORA_35_BASE
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1080922 - Removal of a test manifest that the build system isn't picking up.
+Merge day clobber
\ No newline at end of file
--- a/addon-sdk/source/test/jetpack-package.ini
+++ b/addon-sdk/source/test/jetpack-package.ini
@@ -1,16 +1,16 @@
 [DEFAULT]
 support-files =
   buffers/**
   commonjs-test-adapter/**
   event/**
   fixtures/**
   loader/**
-  libs/**
+  lib/**
   modules/**
   private-browsing/**
   sidebar/**
   tabs/**
   traits/**
   windows/**
   zip/**
   fixtures.js
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -129,12 +129,12 @@
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d259117b4976decbe2f76eeed85218bf0109190f"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
@@ -146,13 +146,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="e5a971282719907f73fb1da964ca40aad67a3be0"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
   <project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
   <project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="7704e16da545f4207812e593743d6743e1afb9c5"/>
 </manifest>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
@@ -140,13 +140,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="cd76b19aafd4229ccf83853d02faef8c51ca8b34"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
   <project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
 </manifest>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "69b4d72a6b80008de044e535d9ff785631bd7f2b", 
+    "revision": "291b607f32e6173d8fe225c644cc7397cdf82fa5", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -124,17 +124,17 @@
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -1,16 +1,16 @@
 # 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/.
 
 MOZ_APP_BASENAME=B2G
 MOZ_APP_VENDOR=Mozilla
 
-MOZ_APP_VERSION=35.0a1
+MOZ_APP_VERSION=36.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_UA_OS_AGNOSTIC=1
 
 MOZ_B2G_VERSION=2.2.0.0-prerelease
 MOZ_B2G_OS_NAME=Boot2Gecko
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1547,17 +1547,17 @@ pref("browser.newtabpage.enabled", true)
 
 // number of rows of newtab grid
 pref("browser.newtabpage.rows", 3);
 
 // number of columns of newtab grid
 pref("browser.newtabpage.columns", 5);
 
 // directory tiles download URL
-pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v2/links/fetch");
+pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v2/links/fetch/%LOCALE%");
 
 // endpoint to send newtab click and view pings
 pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v2/links/");
 
 // Enable the DOM fullscreen API.
 pref("full-screen-api.enabled", true);
 
 // True if the fullscreen API requires approval upon a domain entering fullscreen.
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -56,16 +56,20 @@ input[type=button] {
   top: 15px;
 }
 
 #newtab-intro-what:-moz-locale-dir(rtl) {
   left: 55px;
   right: auto;
 }
 
+#newtab-scrollbox[page-disabled] #newtab-intro-what {
+  display: none;
+}
+
 #newtab-intro-panel {
   color: #6a7b86;
   font-size: 15px;
   line-height: 19px;
   width: 520px;
 }
 
 #newtab-intro-panel h1 {
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -386,17 +386,18 @@ loop.conversation = (function(mozL10n) {
      * @param {Object} progressData The progress data from the websocket.
      * @param {String} previousState The previous state from the websocket.
      */
     _handleWebSocketProgress: function(progressData, previousState) {
       // We only care about the terminated state at the moment.
       if (progressData.state !== "terminated")
         return;
 
-      if (progressData.reason === "cancel") {
+      if (progressData.reason === "cancel" ||
+          progressData.reason === "closed") {
         this._abortIncomingCall();
         return;
       }
 
       if (progressData.reason === "timeout" &&
           (previousState === "init" || previousState === "alerting")) {
         this._abortIncomingCall();
       }
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -386,17 +386,18 @@ loop.conversation = (function(mozL10n) {
      * @param {Object} progressData The progress data from the websocket.
      * @param {String} previousState The previous state from the websocket.
      */
     _handleWebSocketProgress: function(progressData, previousState) {
       // We only care about the terminated state at the moment.
       if (progressData.state !== "terminated")
         return;
 
-      if (progressData.reason === "cancel") {
+      if (progressData.reason === "cancel" ||
+          progressData.reason === "closed") {
         this._abortIncomingCall();
         return;
       }
 
       if (progressData.reason === "timeout" &&
           (previousState === "init" || previousState === "alerting")) {
         this._abortIncomingCall();
       }
--- a/browser/components/loop/standalone/content/css/webapp.css
+++ b/browser/components/loop/standalone/content/css/webapp.css
@@ -18,16 +18,19 @@ body,
   font-family: Open Sans,sans-serif;
 }
 
 .standalone-header {
   border-radius: 4px;
   background: #fff;
   border: 1px solid #E7E7E7;
   box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.03);
+  background-image: url("../shared/img/beta-ribbon.svg#beta-ribbon");
+  background-size: 5rem 5rem;
+  background-repeat: no-repeat;
 }
 
 .header-box {
   padding: 1rem 5rem;
   margin-top: 2rem;
 }
 
 /*
--- a/browser/components/loop/standalone/content/js/webapp.js
+++ b/browser/components/loop/standalone/content/js/webapp.js
@@ -278,17 +278,21 @@ loop.webapp = (function($, _, OT, mozL10
       this.setState({callState: "ringing"});
     },
 
     _cancelOutgoingCall: function() {
       this.props.websocket.cancel();
     },
 
     render: function() {
-      var callState = mozL10n.get("call_progress_" + this.state.callState + "_description");
+      var callStateStringEntityName = "call_progress_" + this.state.callState + "_description";
+      var callState = mozL10n.get(callStateStringEntityName);
+      document.title = mozL10n.get("standalone_title_with_status",
+                                   {clientShortname: mozL10n.get("clientShortname2"),
+                                    currentStatus: mozL10n.get(callStateStringEntityName)});
       return (
         React.DOM.div({className: "container"}, 
           React.DOM.div({className: "container-box"}, 
             React.DOM.header({className: "pending-header header-box"}, 
               ConversationBranding(null)
             ), 
 
             React.DOM.div({id: "cameraPreview"}), 
@@ -514,16 +518,19 @@ loop.webapp = (function($, _, OT, mozL10
       conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
                          .isRequired,
       sdk: React.PropTypes.object.isRequired,
       feedbackApiClient: React.PropTypes.object.isRequired,
       onAfterFeedbackReceived: React.PropTypes.func.isRequired
     },
 
     render: function() {
+      document.title = mozL10n.get("standalone_title_with_status",
+                                   {clientShortname: mozL10n.get("clientShortname2"),
+                                    currentStatus: mozL10n.get("status_conversation_ended")});
       return (
         React.DOM.div({className: "ended-conversation"}, 
           sharedViews.FeedbackView({
             feedbackApiClient: this.props.feedbackApiClient, 
             onAfterFeedbackReceived: this.props.onAfterFeedbackReceived}
           ), 
           sharedViews.ConversationView({
             initiate: false, 
@@ -534,26 +541,30 @@ loop.webapp = (function($, _, OT, mozL10
           )
         )
       );
     }
   });
 
   var StartConversationView = React.createClass({displayName: 'StartConversationView',
     render: function() {
+      document.title = mozL10n.get("clientShortname2");
       return this.transferPropsTo(
         InitiateConversationView({
           title: mozL10n.get("initiate_call_button_label2"), 
           callButtonLabel: mozL10n.get("initiate_audio_video_call_button2")})
       );
     }
   });
 
   var FailedConversationView = React.createClass({displayName: 'FailedConversationView',
     render: function() {
+      document.title = mozL10n.get("standalone_title_with_status",
+                                   {clientShortname: mozL10n.get("clientShortname2"),
+                                    currentStatus: mozL10n.get("status_error")});
       return this.transferPropsTo(
         InitiateConversationView({
           title: mozL10n.get("call_failed_title"), 
           callButtonLabel: mozL10n.get("retry_call_button")})
       );
     }
   });
 
@@ -631,16 +642,19 @@ loop.webapp = (function($, _, OT, mozL10
               client: this.props.client}
             )
           );
         }
         case "pending": {
           return PendingConversationView({websocket: this._websocket});
         }
         case "connected": {
+          document.title = mozL10n.get("standalone_title_with_status",
+                                       {clientShortname: mozL10n.get("clientShortname2"),
+                                        currentStatus: mozL10n.get("status_in_conversation")});
           return (
             sharedViews.ConversationView({
               initiate: true, 
               sdk: this.props.sdk, 
               model: this.props.conversation, 
               video: {enabled: this.props.conversation.hasVideoStream("outgoing")}}
             )
           );
--- a/browser/components/loop/standalone/content/js/webapp.jsx
+++ b/browser/components/loop/standalone/content/js/webapp.jsx
@@ -278,17 +278,21 @@ loop.webapp = (function($, _, OT, mozL10
       this.setState({callState: "ringing"});
     },
 
     _cancelOutgoingCall: function() {
       this.props.websocket.cancel();
     },
 
     render: function() {
-      var callState = mozL10n.get("call_progress_" + this.state.callState + "_description");
+      var callStateStringEntityName = "call_progress_" + this.state.callState + "_description";
+      var callState = mozL10n.get(callStateStringEntityName);
+      document.title = mozL10n.get("standalone_title_with_status",
+                                   {clientShortname: mozL10n.get("clientShortname2"),
+                                    currentStatus: mozL10n.get(callStateStringEntityName)});
       return (
         <div className="container">
           <div className="container-box">
             <header className="pending-header header-box">
               <ConversationBranding />
             </header>
 
             <div id="cameraPreview" />
@@ -514,16 +518,19 @@ loop.webapp = (function($, _, OT, mozL10
       conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
                          .isRequired,
       sdk: React.PropTypes.object.isRequired,
       feedbackApiClient: React.PropTypes.object.isRequired,
       onAfterFeedbackReceived: React.PropTypes.func.isRequired
     },
 
     render: function() {
+      document.title = mozL10n.get("standalone_title_with_status",
+                                   {clientShortname: mozL10n.get("clientShortname2"),
+                                    currentStatus: mozL10n.get("status_conversation_ended")});
       return (
         <div className="ended-conversation">
           <sharedViews.FeedbackView
             feedbackApiClient={this.props.feedbackApiClient}
             onAfterFeedbackReceived={this.props.onAfterFeedbackReceived}
           />
           <sharedViews.ConversationView
             initiate={false}
@@ -534,26 +541,30 @@ loop.webapp = (function($, _, OT, mozL10
           />
         </div>
       );
     }
   });
 
   var StartConversationView = React.createClass({
     render: function() {
+      document.title = mozL10n.get("clientShortname2");
       return this.transferPropsTo(
         <InitiateConversationView
           title={mozL10n.get("initiate_call_button_label2")}
           callButtonLabel={mozL10n.get("initiate_audio_video_call_button2")} />
       );
     }
   });
 
   var FailedConversationView = React.createClass({
     render: function() {
+      document.title = mozL10n.get("standalone_title_with_status",
+                                   {clientShortname: mozL10n.get("clientShortname2"),
+                                    currentStatus: mozL10n.get("status_error")});
       return this.transferPropsTo(
         <InitiateConversationView
           title={mozL10n.get("call_failed_title")}
           callButtonLabel={mozL10n.get("retry_call_button")} />
       );
     }
   });
 
@@ -631,16 +642,19 @@ loop.webapp = (function($, _, OT, mozL10
               client={this.props.client}
             />
           );
         }
         case "pending": {
           return <PendingConversationView websocket={this._websocket} />;
         }
         case "connected": {
+          document.title = mozL10n.get("standalone_title_with_status",
+                                       {clientShortname: mozL10n.get("clientShortname2"),
+                                        currentStatus: mozL10n.get("status_in_conversation")});
           return (
             <sharedViews.ConversationView
               initiate={true}
               sdk={this.props.sdk}
               model={this.props.conversation}
               video={{enabled: this.props.conversation.hasVideoStream("outgoing")}}
             />
           );
--- a/browser/components/loop/standalone/content/l10n/loop.en-US.properties
+++ b/browser/components/loop/standalone/content/l10n/loop.en-US.properties
@@ -114,8 +114,17 @@ rooms_room_full_label=There are already 
 rooms_room_full_call_to_action_nonFx_label=Download {{brandShortname}} to start your own
 rooms_room_full_call_to_action_label=Learn more about {{clientShortname}} »
 rooms_room_joined_label=Someone has joined the conversation!
 rooms_room_join_label=Join the conversation
 
 brand_website=https://www.mozilla.org/firefox/
 privacy_website=https://www.mozilla.org/privacy/
 legal_website=/legal/terms/
+
+## LOCALIZATION_NOTE(standalone_title_with_status): {{clientShortname}} will be
+## replaced by the brand name and {{currentStatus}} will be replaced
+## by the current call status (Connecting, Ringing, etc.)
+standalone_title_with_status={{clientShortname}} — {{currentStatus}}
+status_in_conversation=In conversation
+status_conversation_ended=Conversation ended
+status_error=Something went wrong
+
--- a/browser/components/loop/test/desktop-local/conversation_test.js
+++ b/browser/components/loop/test/desktop-local/conversation_test.js
@@ -401,16 +401,56 @@ describe("loop.conversation", function()
                   sandbox.clock.tick(1);
 
                   sinon.assert.calledOnce(window.close);
                   done();
                 });
               });
             });
 
+            describe("progress - terminated - closed", function() {
+              it("should stop alerting", function(done) {
+                promise.then(function() {
+                  icView._websocket.trigger("progress", {
+                    state: "terminated",
+                    reason: "closed"
+                  });
+
+                  sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
+                  done();
+                });
+              });
+
+              it("should close the websocket", function(done) {
+                promise.then(function() {
+                  icView._websocket.trigger("progress", {
+                    state: "terminated",
+                    reason: "closed"
+                  });
+
+                  sinon.assert.calledOnce(icView._websocket.close);
+                  done();
+                });
+              });
+
+              it("should close the window", function(done) {
+                promise.then(function() {
+                  icView._websocket.trigger("progress", {
+                    state: "terminated",
+                    reason: "closed"
+                  });
+
+                  sandbox.clock.tick(1);
+
+                  sinon.assert.calledOnce(window.close);
+                  done();
+                });
+              });
+            });
+
             describe("progress - terminated - timeout (previousState = alerting)", function() {
               it("should stop alerting", function(done) {
                 promise.then(function() {
                   icView._websocket.trigger("progress", {
                     state: "terminated",
                     reason: "timeout"
                   }, "alerting");
 
deleted file mode 100644
--- a/browser/components/sessionstore/RevivableWindows.jsm
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["RevivableWindows"];
-
-// List of closed windows that we can revive when closing
-// windows in succession until the browser quits.
-let closedWindows = [];
-
-/**
- * This module keeps track of closed windows that are revivable. On Windows
- * and Linux we can revive windows before saving to disk - i.e. moving them
- * from state._closedWindows[] to state.windows[] so that they're opened
- * automatically on next startup. This feature lets us properly support
- * closing windows in succession until the browser quits.
- *
- * The length of the list is not capped by max_undo_windows unlike
- * state._closedWindows[].
- */
-this.RevivableWindows = Object.freeze({
-  // Returns whether there are windows to revive.
-  get isEmpty() {
-    return closedWindows.length == 0;
-  },
-
-  // Add a window to the list.
-  add(winState) {
-#ifndef XP_MACOSX
-    closedWindows.push(winState);
-#endif
-  },
-
-  // Get the list of revivable windows.
-  get() {
-    return [...closedWindows];
-  },
-
-  // Clear the list of revivable windows.
-  clear() {
-    closedWindows.length = 0;
-  }
-});
--- a/browser/components/sessionstore/SessionSaver.jsm
+++ b/browser/components/sessionstore/SessionSaver.jsm
@@ -14,18 +14,16 @@ Cu.import("resource://gre/modules/Timer.
 Cu.import("resource://gre/modules/Services.jsm", this);
 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", this);
 
 XPCOMUtils.defineLazyModuleGetter(this, "console",
   "resource://gre/modules/devtools/Console.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter",
   "resource:///modules/sessionstore/PrivacyFilter.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "RevivableWindows",
-  "resource:///modules/sessionstore/RevivableWindows.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
   "resource:///modules/sessionstore/SessionStore.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionFile",
   "resource:///modules/sessionstore/SessionFile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 // Minimal interval between two save operations (in milliseconds).
@@ -202,34 +200,33 @@ let SessionSaverInternal = {
 
     // Make sure that we keep the previous session if we started with a single
     // private window and no non-private windows have been opened, yet.
     if (state.deferredInitialState) {
       state.windows = state.deferredInitialState.windows || [];
       delete state.deferredInitialState;
     }
 
-    // We want to revive closed windows that have been closed in succession
-    // without any user action in between closing those. This happens here in
-    // the SessionSaver because we only want to revive when saving to disk.
-    // On Mac OS X this list will always be empty.
-    let windowsToRevive = RevivableWindows.get();
-    state.windows.unshift(...windowsToRevive);
-    let revivedWindows = state._closedWindows.splice(0, windowsToRevive.length);
-#ifdef DEBUG
-    // Check that the windows to revive equal the windows
-    // that we removed from the list of closed windows.
-    let match = revivedWindows.every((win, idx) => {
-      return win == windowsToRevive[windowsToRevive.length - 1 - idx];
-    });
+#ifndef XP_MACOSX
+    // We want to restore closed windows that are marked with _shouldRestore.
+    // We're doing this here because we want to control this only when saving
+    // the file.
+    while (state._closedWindows.length) {
+      let i = state._closedWindows.length - 1;
 
-    if (!match) {
-      throw new Error("SessionStore: revived windows didn't match closed windows");
+      if (!state._closedWindows[i]._shouldRestore) {
+        // We only need to go until _shouldRestore
+        // is falsy since we're going in reverse.
+        break;
+      }
+
+      delete state._closedWindows[i]._shouldRestore;
+      state.windows.unshift(state._closedWindows.pop());
     }
-#endif DEBUG
+#endif
 
     stopWatchFinish("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
     return this._writeState(state);
   },
 
   /**
    * Saves the current session state. Collects data asynchronously and calls
    * _saveState() to collect data again (with a cache hit rate of hopefully
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -102,18 +102,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource://gre/modules/devtools/Console.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
   "resource:///modules/RecentWindow.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "GlobalState",
   "resource:///modules/sessionstore/GlobalState.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter",
   "resource:///modules/sessionstore/PrivacyFilter.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "RevivableWindows",
-  "resource:///modules/sessionstore/RevivableWindows.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RunState",
   "resource:///modules/sessionstore/RunState.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager",
   "resource:///modules/devtools/scratchpad-manager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionSaver",
   "resource:///modules/sessionstore/SessionSaver.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionCookies",
   "resource:///modules/sessionstore/SessionCookies.jsm");
@@ -698,19 +696,17 @@ let SessionStoreInternal = {
         this.onTabHide(win, aEvent.originalTarget);
         break;
       case "TabPinned":
       case "TabUnpinned":
       case "SwapDocShells":
         this.saveStateDelayed(win);
         break;
     }
-
-    // Any event handled here indicates a user action.
-    RevivableWindows.clear();
+    this._clearRestoringWindows();
   },
 
   /**
    * Generate a unique window identifier
    * @return string
    *         A unique string to identify a window
    */
   _generateWindowID: function ssi_generateWindowID() {
@@ -1012,16 +1008,22 @@ let SessionStoreInternal = {
 
       if (isFullyLoaded) {
         winData.title = tabbrowser.selectedBrowser.contentTitle || tabbrowser.selectedTab.label;
         winData.title = this._replaceLoadingTitle(winData.title, tabbrowser,
                                                   tabbrowser.selectedTab);
         SessionCookies.update([winData]);
       }
 
+#ifndef XP_MACOSX
+      // Until we decide otherwise elsewhere, this window is part of a series
+      // of closing windows to quit.
+      winData._shouldRestore = true;
+#endif
+
       // Store the window's close date to figure out when each individual tab
       // was closed. This timestamp should allow re-arranging data based on how
       // recently something was closed.
       winData.closedAt = Date.now();
 
       // Save non-private windows if they have at
       // least one saveable tab or are the last window.
       if (!winData.isPrivate) {
@@ -1032,30 +1034,27 @@ let SessionStoreInternal = {
         let hasSaveableTabs = winData.tabs.some(this._shouldSaveTabState);
 
         // When closing windows one after the other until Firefox quits, we
         // will move those closed in series back to the "open windows" bucket
         // before writing to disk. If however there is only a single window
         // with tabs we deem not worth saving then we might end up with a
         // random closed or even a pop-up window re-opened. To prevent that
         // we explicitly allow saving an "empty" window state.
-        let numOpenWindows = Object.keys(this._windows).length;
-        let isLastWindow = numOpenWindows == 1 && RevivableWindows.isEmpty;
+        let isLastWindow =
+          Object.keys(this._windows).length == 1 &&
+          !this._closedWindows.some(win => win._shouldRestore || false);
 
         if (hasSaveableTabs || isLastWindow) {
           // we don't want to save the busy state
           delete winData.busy;
 
           this._closedWindows.unshift(winData);
           this._capClosedWindows();
         }
-
-        // Until we decide otherwise elsewhere, this window
-        // is part of a series of closing windows to quit.
-        RevivableWindows.add(winData);
       }
 
       // clear this window from the list
       delete this._windows[aWindow.__SSi];
 
       // save the state without this window to disk
       this.saveStateDelayed();
     }
@@ -1151,28 +1150,27 @@ let SessionStoreInternal = {
     // also clear all data about closed tabs and windows
     for (let ix in this._windows) {
       if (ix in openWindows) {
         this._windows[ix]._closedTabs = [];
       } else {
         delete this._windows[ix];
       }
     }
-
     // also clear all data about closed windows
     this._closedWindows = [];
-    RevivableWindows.clear();
-
     // give the tabbrowsers a chance to clear their histories first
     var win = this._getMostRecentBrowserWindow();
     if (win) {
       win.setTimeout(() => SessionSaver.run(), 0);
     } else if (RunState.isRunning) {
       SessionSaver.run();
     }
+
+    this._clearRestoringWindows();
   },
 
   /**
    * On purge of domain data
    * @param aData
    *        String domain data
    */
   onPurgeDomainData: function ssi_onPurgeDomainData(aData) {
@@ -1216,22 +1214,21 @@ let SessionStoreInternal = {
         // some duplication from restoreHistory - make sure we get the correct title
         let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
         if (activeIndex >= selectedTab.entries.length)
           activeIndex = selectedTab.entries.length - 1;
         this._closedWindows[ix].title = selectedTab.entries[activeIndex].title;
       }
     }
 
-    // Purging domain data indicates a user action.
-    RevivableWindows.clear();
-
     if (RunState.isRunning) {
       SessionSaver.run();
     }
+
+    this._clearRestoringWindows();
   },
 
   /**
    * On preference change
    * @param aData
    *        String preference changed
    */
   onPrefChange: function ssi_onPrefChange(aData) {
@@ -3345,16 +3342,31 @@ let SessionStoreInternal = {
       normalWindowIndex++;
     if (normalWindowIndex >= this._max_windows_undo)
       spliceTo = normalWindowIndex + 1;
 #endif
     this._closedWindows.splice(spliceTo, this._closedWindows.length);
   },
 
   /**
+   * Clears the set of windows that are "resurrected" before writing to disk to
+   * make closing windows one after the other until shutdown work as expected.
+   *
+   * This function should only be called when we are sure that there has been
+   * a user action that indicates the browser is actively being used and all
+   * windows that have been closed before are not part of a series of closing
+   * windows.
+   */
+  _clearRestoringWindows: function ssi_clearRestoringWindows() {
+    for (let i = 0; i < this._closedWindows.length; i++) {
+      delete this._closedWindows[i]._shouldRestore;
+    }
+  },
+
+  /**
    * Reset state to prepare for a new session state to be restored.
    */
   _resetRestoringState: function ssi_initRestoringState() {
     TabRestoreQueue.reset();
     this._tabsRestoringCount = 0;
   },
 
   /**
--- a/browser/components/sessionstore/moz.build
+++ b/browser/components/sessionstore/moz.build
@@ -41,13 +41,12 @@ EXTRA_JS_MODULES.sessionstore = [
     'SessionWorker.jsm',
     'TabAttributes.jsm',
     'TabState.jsm',
     'TabStateCache.jsm',
     'Utils.jsm',
 ]
 
 EXTRA_PP_JS_MODULES.sessionstore += [
-    'RevivableWindows.jsm',
     'SessionSaver.jsm',
     'SessionStore.jsm',
 ]
 
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -76,17 +76,16 @@ skip-if = buildapp == 'mulet'
 [browser_frametree.js]
 [browser_frame_history.js]
 [browser_global_store.js]
 [browser_history_cap.js]
 [browser_label_and_icon.js]
 [browser_merge_closed_tabs.js]
 [browser_pageStyle.js]
 [browser_privatetabs.js]
-[browser_revive_windows.js]
 [browser_scrollPositions.js]
 [browser_sessionHistory.js]
 skip-if = e10s
 [browser_sessionStorage.js]
 skip-if = e10s
 [browser_swapDocShells.js]
 skip-if = e10s # See bug 918634
 [browser_telemetry.js]
deleted file mode 100644
--- a/browser/components/sessionstore/test/browser_revive_windows.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-const IS_MAC = ("nsILocalFileMac" in Ci);
-const URL_PREFIX = "about:mozilla?t=browser_revive_windows&r=";
-const PREF_MAX_UNDO = "browser.sessionstore.max_windows_undo";
-
-const URL_MAIN_WINDOW = URL_PREFIX + Math.random();
-const URL_ADD_WINDOW1 = URL_PREFIX + Math.random();
-const URL_ADD_WINDOW2 = URL_PREFIX + Math.random();
-const URL_CLOSED_WINDOW = URL_PREFIX + Math.random();
-
-add_task(function* setup() {
-  registerCleanupFunction(() => Services.prefs.clearUserPref(PREF_MAX_UNDO));
-});
-
-/**
- * This test ensure that when closing windows in succession until the browser
- * quits we are able to revive more windows than we keep around for the
- * "Undo Close Window" feature.
- */
-add_task(function* test_revive_windows() {
-  // We can restore a single window max.
-  Services.prefs.setIntPref(PREF_MAX_UNDO, 1);
-
-  // Clear list of closed windows.
-  forgetClosedWindows();
-
-  let windows = [];
-
-  // Create three windows.
-  for (let i = 0; i < 3; i++) {
-    let win = yield promiseNewWindow();
-    windows.push(win);
-
-    let tab = win.gBrowser.addTab("about:mozilla");
-    yield promiseBrowserLoaded(tab.linkedBrowser);
-  }
-
-  // Create a private window.
-  // This window must not be revived.
-  {
-    let win = yield promiseNewWindow({private: true});
-    windows.push(win);
-
-    let tab = win.gBrowser.addTab("about:mozilla");
-    yield promiseBrowserLoaded(tab.linkedBrowser);
-  }
-
-  // Close all windows.
-  for (let win of windows) {
-    yield promiseWindowClosed(win);
-  }
-
-  is(ss.getClosedWindowCount(), 1, "one window restorable");
-
-  // Save to disk and read.
-  let state = JSON.parse(yield promiseRecoveryFileContents());
-
-  // Check number of windows.
-  if (IS_MAC) {
-    is(state.windows.length, 1, "one open window");
-    is(state._closedWindows.length, 1, "one closed window");
-  } else {
-    is(state.windows.length, 4, "four open windows");
-    is(state._closedWindows.length, 0, "closed windows");
-  }
-});
-
-/**
- * This test ensures that when closing windows one after the other until the
- * browser shuts down (on Windows and Linux) we revive closed windows in the
- * right order.
- */
-add_task(function* test_revive_windows_order() {
-  // We can restore up to three windows max.
-  Services.prefs.setIntPref(PREF_MAX_UNDO, 3);
-
-  // Clear list of closed windows.
-  forgetClosedWindows();
-
-  let tab = gBrowser.addTab(URL_MAIN_WINDOW);
-  yield promiseBrowserLoaded(tab.linkedBrowser);
-  TabState.flush(tab.linkedBrowser);
-  registerCleanupFunction(() => gBrowser.removeTab(tab));
-
-  let win0 = yield promiseNewWindow();
-  let tab0 = win0.gBrowser.addTab(URL_CLOSED_WINDOW);
-  yield promiseBrowserLoaded(tab0.linkedBrowser);
-
-  yield promiseWindowClosed(win0);
-  let data = ss.getClosedWindowData();
-  ok(data.contains(URL_CLOSED_WINDOW), "window is restorable");
-
-  let win1 = yield promiseNewWindow();
-  let tab1 = win1.gBrowser.addTab(URL_ADD_WINDOW1);
-  yield promiseBrowserLoaded(tab1.linkedBrowser);
-
-  let win2 = yield promiseNewWindow();
-  let tab2 = win2.gBrowser.addTab(URL_ADD_WINDOW2);
-  yield promiseBrowserLoaded(tab2.linkedBrowser);
-
-  // Close both windows so that |win1| will be opened first and would be
-  // behind |win2| that was closed later.
-  yield promiseWindowClosed(win1);
-  yield promiseWindowClosed(win2);
-
-  // Repeat the checks once.
-  for (let i = 0; i < 2; i++) {
-    info(`checking window data, iteration #${i}`);
-    let contents = yield promiseRecoveryFileContents();
-    let {windows, _closedWindows: closedWindows} = JSON.parse(contents);
-
-    if (IS_MAC) {
-      // Check number of windows.
-      is(windows.length, 1, "one open window");
-      is(closedWindows.length, 3, "three closed windows");
-
-      // Check open window.
-      ok(JSON.stringify(windows).contains(URL_MAIN_WINDOW),
-        "open window is correct");
-
-      // Check closed windows.
-      ok(JSON.stringify(closedWindows[0]).contains(URL_ADD_WINDOW2),
-        "correct first additional window");
-      ok(JSON.stringify(closedWindows[1]).contains(URL_ADD_WINDOW1),
-        "correct second additional window");
-      ok(JSON.stringify(closedWindows[2]).contains(URL_CLOSED_WINDOW),
-        "correct main window");
-    } else {
-      // Check number of windows.
-      is(windows.length, 3, "three open windows");
-      is(closedWindows.length, 1, "one closed window");
-
-      // Check closed window.
-      ok(JSON.stringify(closedWindows).contains(URL_CLOSED_WINDOW),
-        "closed window is correct");
-
-      // Check that windows are in the right order.
-      ok(JSON.stringify(windows[0]).contains(URL_ADD_WINDOW1),
-        "correct first additional window");
-      ok(JSON.stringify(windows[1]).contains(URL_ADD_WINDOW2),
-        "correct second additional window");
-      ok(JSON.stringify(windows[2]).contains(URL_MAIN_WINDOW),
-        "correct main window");
-    }
-  }
-});
-
-function promiseNewWindow(opts = {private: false}) {
-  return new Promise(resolve => whenNewWindowLoaded(opts, resolve));
-}
-
-function forgetClosedWindows() {
-  while (ss.getClosedWindowCount()) {
-    ss.forgetClosedWindow(0);
-  }
-}
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-35.0a1
+36.0a1
--- a/browser/devtools/layoutview/test/browser.ini
+++ b/browser/devtools/layoutview/test/browser.ini
@@ -9,13 +9,14 @@ support-files =
 [browser_layoutview.js]
 [browser_layoutview_guides.js]
 # browser_layoutview_guides.js should be re-enabled when bug 1029451 is fixed.
 skip-if = true
 [browser_layoutview_rotate-labels-on-sides.js]
 [browser_layoutview_update-after-navigation.js]
 [browser_layoutview_update-after-reload.js]
 [browser_layoutview_update-in-iframes.js]
+skip-if = true # Bug 1020038 layout-view updates for iframe elements changes
 [browser_editablemodel.js]
 # [browser_editablemodel_allproperties.js]
 # Disabled for too many intermittent failures (bug 1009322)
 [browser_editablemodel_border.js]
 [browser_editablemodel_stylerules.js]
--- a/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
+++ b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
@@ -103,8 +103,13 @@ loop-call-button2.tooltiptext = Start a 
 social-share-button.label = Share This Page
 social-share-button.tooltiptext = Share This Page
 
 panic-button.label = Forget
 panic-button.tooltiptext = Forget about some browsing history
 
 web-apps-button.label = Apps
 web-apps-button.tooltiptext = Discover Apps
+
+# LOCALIZATION NOTE(devtools-webide-button.label, devtools-webide-button.tooltiptext):
+# widget is only visible after WebIDE has been started once (Tools > Web Developers > WebIDE)
+devtools-webide-button.label = WebIDE
+devtools-webide-button.tooltiptext = Open WebIDE
--- a/browser/modules/DirectoryLinksProvider.jsm
+++ b/browser/modules/DirectoryLinksProvider.jsm
@@ -178,16 +178,19 @@ let DirectoryLinksProvider = {
   _removePrefsObserver: function DirectoryLinksProvider_removeObserver() {
     for (let pref in this._observedPrefs) {
       let prefName = this._observedPrefs[pref];
       Services.prefs.removeObserver(prefName, this);
     }
   },
 
   _fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {
+    // Replace with the same display locale used for selecting links data
+    uri = uri.replace("%LOCALE%", this.locale);
+
     let deferred = Promise.defer();
     let xmlHttp = new XMLHttpRequest();
 
     let self = this;
     xmlHttp.onload = function(aResponse) {
       let json = this.responseText;
       if (this.status && this.status != 200) {
         json = "{}";
@@ -201,24 +204,22 @@ let DirectoryLinksProvider = {
         });
     };
 
     xmlHttp.onerror = function(e) {
       deferred.reject("Fetching " + uri + " results in error code: " + e.target.status);
     };
 
     try {
-      xmlHttp.open('POST', uri);
+      xmlHttp.open("GET", uri);
       // Override the type so XHR doesn't complain about not well-formed XML
       xmlHttp.overrideMimeType(DIRECTORY_LINKS_TYPE);
       // Set the appropriate request type for servers that require correct types
       xmlHttp.setRequestHeader("Content-Type", DIRECTORY_LINKS_TYPE);
-      xmlHttp.send(JSON.stringify({
-        locale: this.locale,
-      }));
+      xmlHttp.send();
     } catch (e) {
       deferred.reject("Error fetching " + uri);
       Cu.reportError(e);
     }
     return deferred.promise;
   },
 
   /**
--- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
+++ b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
@@ -48,32 +48,29 @@ const kPingUrl = kBaseUrl + kPingPath;
 Services.prefs.setCharPref(kLocalePref, "en-US");
 Services.prefs.setCharPref(kSourceUrlPref, kTestURL);
 Services.prefs.setCharPref(kPingUrlPref, kPingUrl);
 Services.prefs.setBoolPref(kNewtabEnhancedPref, true);
 
 const kHttpHandlerData = {};
 kHttpHandlerData[kExamplePath] = {"en-US": [{"url":"http://example.com","title":"RemoteSource"}]};
 
-const expectedBodyObject = {locale: DirectoryLinksProvider.locale};
 const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
                               "nsIBinaryInputStream",
                               "setInputStream");
 
+let gLastRequestPath;
 function getHttpHandler(path) {
   let code = 200;
   let body = JSON.stringify(kHttpHandlerData[path]);
   if (path == kFailPath) {
     code = 204;
   }
   return function(aRequest, aResponse) {
-    let bodyStream = new BinaryInputStream(aRequest.bodyInputStream);
-    let bodyObject = JSON.parse(NetUtil.readInputStreamToString(bodyStream, bodyStream.available()));
-    isIdentical(bodyObject, expectedBodyObject);
-
+    gLastRequestPath = aRequest.path;
     aResponse.setStatusLine(null, code);
     aResponse.setHeader("Content-Type", "application/json");
     aResponse.write(body);
   };
 }
 
 function isIdentical(actual, expected) {
   if (expected == null) {
@@ -126,17 +123,19 @@ function promiseDirectoryDownloadOnPrefC
   let oldValue = Services.prefs.getCharPref(pref);
   if (oldValue != newValue) {
     // if the preference value is already equal to newValue
     // the pref service will not call our observer and we
     // deadlock. Hence only setup observer if values differ
     let observer = new LinksChangeObserver();
     DirectoryLinksProvider.addObserver(observer);
     Services.prefs.setCharPref(pref, newValue);
-    return observer.deferred.promise;
+    return observer.deferred.promise.then(() => {
+      DirectoryLinksProvider.removeObserver(observer);
+    });
   }
   return Promise.resolve();
 }
 
 function promiseSetupDirectoryLinksProvider(options = {}) {
   return Task.spawn(function() {
     let linksURL = options.linksURL || kTestURL;
     yield DirectoryLinksProvider.init();
@@ -291,17 +290,18 @@ add_task(function test_fetchAndCacheLink
   let data = yield readJsonFile();
   isIdentical(data, kURLData);
 });
 
 add_task(function test_fetchAndCacheLinks_remote() {
   yield DirectoryLinksProvider.init();
   yield cleanJsonFile();
   // this must trigger directory links json download and save it to cache file
-  yield DirectoryLinksProvider._fetchAndCacheLinks(kExampleURL);
+  yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kExampleURL + "%LOCALE%");
+  do_check_eq(gLastRequestPath, kExamplePath + "en-US");
   let data = yield readJsonFile();
   isIdentical(data, kHttpHandlerData[kExamplePath]);
 });
 
 add_task(function test_fetchAndCacheLinks_malformedURI() {
   yield DirectoryLinksProvider.init();
   yield cleanJsonFile();
   let someJunk = "some junk";
@@ -331,17 +331,18 @@ add_task(function test_fetchAndCacheLink
   // File should be empty.
   let data = yield readJsonFile();
   isIdentical(data, "");
 });
 
 add_task(function test_fetchAndCacheLinks_non200Status() {
   yield DirectoryLinksProvider.init();
   yield cleanJsonFile();
-  yield DirectoryLinksProvider._fetchAndCacheLinks(kFailURL);
+  yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kFailURL);
+  do_check_eq(gLastRequestPath, kFailPath);
   let data = yield readJsonFile();
   isIdentical(data, {});
 });
 
 // To test onManyLinksChanged observer, trigger a fetch
 add_task(function test_DirectoryLinksProvider__linkObservers() {
   yield DirectoryLinksProvider.init();
 
@@ -503,16 +504,17 @@ add_task(function test_DirectoryLinksPro
   yield cleanJsonFile();
   // ensure that provider does not think it needs to download
   do_check_false(DirectoryLinksProvider._needsDownload);
 
   // change the source URL, which should force directory download
   yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kExampleURL);
   // then wait for testObserver to fire and test that json is downloaded
   yield testObserver.deferred.promise;
+  do_check_eq(gLastRequestPath, kExamplePath);
   let data = yield readJsonFile();
   isIdentical(data, kHttpHandlerData[kExamplePath]);
 
   yield promiseCleanDirectoryLinksProvider();
 });
 
 add_task(function test_DirectoryLinksProvider_fetchDirectoryOnShow() {
   yield promiseSetupDirectoryLinksProvider();
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.pl.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-35.0a1
+36.0a1
--- a/dom/mobileconnection/gonk/MobileConnectionService.js
+++ b/dom/mobileconnection/gonk/MobileConnectionService.js
@@ -945,16 +945,21 @@ MobileConnectionService.prototype = {
 
   _updateDebugFlag: function() {
     try {
       DEBUG = RIL.DEBUG_RIL ||
               Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
     } catch (e) {}
   },
 
+  _broadcastCdmaInfoRecordSystemMessage: function(aMessage) {
+    // TODO: Bug 1072808, Broadcast System Message with proxy.
+    gSystemMessenger.broadcastMessage("cdma-info-rec-received", aMessage);
+  },
+
   /**
    * nsIMobileConnectionService interface.
    */
   get numItems() {
     return this._providers.length;
   },
 
   getItemByServiceId: function(aServiceId) {
@@ -1162,16 +1167,121 @@ MobileConnectionService.prototype = {
       debug("notifyCFStateChanged for " + aClientId);
     }
 
     let provider = this.getItemByServiceId(aClientId);
     provider.notifyCFStateChanged(aAction, aReason, aNumber, aTimeSeconds,
                                   aServiceClass);
   },
 
+  notifyCdmaInfoRecDisplay: function(aClientId, aDisplay) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      display: aDisplay
+    });
+  },
+
+  notifyCdmaInfoRecCalledPartyNumber: function(aClientId, aType, aPlan, aNumber,
+                                               aPi, aSi) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      calledNumber: {
+        type: aType,
+        plan: aPlan,
+        number: aNumber,
+        pi: aPi,
+        si: aSi
+      }
+    });
+  },
+
+  notifyCdmaInfoRecCallingPartyNumber: function(aClientId, aType, aPlan, aNumber,
+                                                aPi, aSi) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      callingNumber: {
+        type: aType,
+        plan: aPlan,
+        number: aNumber,
+        pi: aPi,
+        si: aSi
+      }
+    });
+  },
+
+  notifyCdmaInfoRecConnectedPartyNumber: function(aClientId, aType, aPlan, aNumber,
+                                                  aPi, aSi) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      connectedNumber: {
+        type: aType,
+        plan: aPlan,
+        number: aNumber,
+        pi: aPi,
+        si: aSi
+      }
+    });
+  },
+
+  notifyCdmaInfoRecSignal: function(aClientId, aType, aAlertPitch, aSignal){
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      signal: {
+        type: aType,
+        alertPitch: aAlertPitch,
+        signal: aSignal
+      }
+    });
+  },
+
+  notifyCdmaInfoRecRedirectingNumber: function(aClientId, aType, aPlan, aNumber,
+                                               aPi, aSi, aReason) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      redirect: {
+        type: aType,
+        plan: aPlan,
+        number: aNumber,
+        pi: aPi,
+        si: aSi,
+        reason: aReason
+      }
+    });
+  },
+
+  notifyCdmaInfoRecLineControl: function(aClientId, aPolarityIncluded, aToggle,
+                                         aReverse, aPowerDenial) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      lineControl: {
+        polarityIncluded: aPolarityIncluded,
+        toggle: aToggle,
+        reverse: aReverse,
+        powerDenial: aPowerDenial
+      }
+    });
+  },
+
+  notifyCdmaInfoRecClir: function(aClientId, aCause) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      clirCause: aCause
+    });
+  },
+
+  notifyCdmaInfoRecAudioControl: function(aClientId, aUplink, aDownLink) {
+    this._broadcastCdmaInfoRecordSystemMessage({
+      clientId: aClientId,
+      audioControl: {
+        upLink: aUplink,
+        downLink: aDownLink
+      }
+    });
+  },
+
   /**
    * nsIObserver interface.
    */
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
       case NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID:
         for (let i = 0; i < this.numItems; i++) {
           let provider = this._providers[i];
--- a/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl
+++ b/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl
@@ -4,17 +4,17 @@
 
 #include "nsIMobileConnectionService.idl"
 
 %{C++
 #define GONK_MOBILECONNECTION_SERVICE_CONTRACTID \
         "@mozilla.org/mobileconnection/gonkmobileconnectionservice;1"
 %}
 
-[scriptable, uuid(b0310517-e7f6-4fa5-a52e-fa6ff35c8fc1)]
+[scriptable, uuid(2d574f0e-4a02-11e4-b1b3-cbc14b7608ce)]
 interface nsIGonkMobileConnectionService : nsIMobileConnectionService
 {
   void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo);
 
   void notifyVoiceInfoChanged(in unsigned long clientId, in jsval voiceInfo);
 
   void notifyDataInfoChanged(in unsigned long clientId, in jsval dataInfo);
 
@@ -48,9 +48,210 @@ interface nsIGonkMobileConnectionService
                                     in DOMString network);
 
   void notifyCFStateChanged(in unsigned long clientId,
                             in unsigned short action,
                             in unsigned short reason,
                             in DOMString number,
                             in unsigned short timeSeconds,
                             in unsigned short serviceClass);
+
+  /**
+   * Notify Display Info from received Cdma-Info-Record.
+   * See 3.7.4.1 Display in 3GPP2 C.S0005-F.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param display
+            The string to be displayed.
+   */
+  void notifyCdmaInfoRecDisplay(in unsigned long clientId,
+                                in DOMString display);
+
+  /**
+   * Notify Called Party Number from received Cdma-Info-Record.
+   * See 3.7.4.2 Called Party Number in 3GPP2 C.S0005-F.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param type
+   *        The type of number. (3-bit binary)
+   *        See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
+   * @param plan
+   *        The numbering plan. (4-bit binary)
+   *        See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
+   * @param number
+   *        The string presentation of the number.
+   * @param pi (2-bit binary)
+   *        The Presentation indicator of the number.
+   *        See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
+   * @param si (2-bit binary)
+   *        The Screening Indicator of the number.
+   *        See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
+   */
+  void notifyCdmaInfoRecCalledPartyNumber(in unsigned long clientId,
+                                          in unsigned short type,
+                                          in unsigned short plan,
+                                          in DOMString number,
+                                          in unsigned short pi,
+                                          in unsigned short si);
+
+  /**
+   * Notify Calling Party Number from received Cdma-Info-Record.
+   * See 3.7.4.3 Calling Party Number in 3GPP2 C.S0005-F.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param type
+   *        The type of number. (3-bit binary)
+   *        See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
+   * @param plan
+   *        The numbering plan. (4-bit binary)
+   *        See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
+   * @param number
+   *        The string presentation of the number.
+   * @param pi (2-bit binary)
+   *        The Presentation indicator of the number.
+   *        See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
+   * @param si (2-bit binary)
+   *        The Screening Indicator of the number.
+   *        See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
+   */
+  void notifyCdmaInfoRecCallingPartyNumber(in unsigned long clientId,
+                                           in unsigned short type,
+                                           in unsigned short plan,
+                                           in DOMString number,
+                                           in unsigned short pi,
+                                           in unsigned short si);
+
+  /**
+   * Notify Connected Party Number from received Cdma-Info-Record.
+   * See 3.7.4.4 Connected Party Number in 3GPP2 C.S0005-F.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param type
+   *        The type of number. (3-bit binary)
+   *        See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
+   * @param plan
+   *        The numbering plan. (4-bit binary)
+   *        See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
+   * @param number
+   *        The string presentation of the number.
+   * @param pi (2-bit binary)
+   *        The Presentation indicator of the number.
+   *        See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
+   * @param si (2-bit binary)
+   *        The Screening Indicator of the number.
+   *        See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
+   */
+  void notifyCdmaInfoRecConnectedPartyNumber(in unsigned long clientId,
+                                             in unsigned short type,
+                                             in unsigned short plan,
+                                             in DOMString number,
+                                             in unsigned short pi,
+                                             in unsigned short si);
+
+  /**
+   * Notify Signal Info from received Cdma-Info-Record.
+   * See 3.7.4.5 Signal in 3GPP2 C.S0005-F.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param type
+   *        The signal type. (2-bit binary)
+   *        See Table 3.7.5.5-1 in 3GPP2 C.S0005-F.
+   * @param alertPitch
+   *        The pitch of the alerting signal. (2-bit binary)
+   *        See Table 3.7.5.5-2 in 3GPP2 C.S0005-F.
+   * @param signal
+   *        The signal code. (6-bit binary)
+   *        See Table 3.7.5.5-3, 3.7.5.5-4, 3.7.5.5-5 in 3GPP2 C.S0005-F.
+   */
+  void notifyCdmaInfoRecSignal(in unsigned long clientId,
+                               in unsigned short type,
+                               in unsigned short alertPitch,
+                               in unsigned short signal);
+
+  /**
+   * Notify Redirecting Number from received Cdma-Info-Record.
+   * See 3.7.4.11 Redirecting Number in 3GPP2 C.S0005-F.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param type
+   *        The type of number. (3-bit binary)
+   *        See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
+   * @param plan
+   *        The numbering plan. (4-bit binary)
+   *        See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
+   * @param number
+   *        The string presentation of the number.
+   * @param pi (2-bit binary)
+   *        The Presentation indicator of the number.
+   *        See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
+   * @param si (2-bit binary)
+   *        The Screening Indicator of the number.
+   *        See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
+   * @param reason (4-bit binary)
+   *        The redirection reason.
+   *        See Table 3.7.5.11-1 in 3GPP2 C.S0005-F.
+   */
+  void notifyCdmaInfoRecRedirectingNumber(in unsigned long clientId,
+                                          in unsigned short type,
+                                          in unsigned short plan,
+                                          in DOMString number,
+                                          in unsigned short pi,
+                                          in unsigned short si,
+                                          in unsigned short reason);
+
+  /**
+   * Notify Line Control from received Cdma-Info-Record.
+   * See 3.7.4.15 Line Control in 3GPP2 C.S0005-F.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param polarityIncluded (1-bit)
+   *        Polarity parameter included.
+   * @param toggle (1-bit)
+   *        Toggle mode.
+   * @param reverse (1-bit)
+   *        Reverse polarity.
+   * @param powerDenial (8-bit)
+   *        Power denial timeout.
+   */
+  void notifyCdmaInfoRecLineControl(in unsigned long clientId,
+                                    in unsigned short polarityIncluded,
+                                    in unsigned short toggle,
+                                    in unsigned short reverse,
+                                    in unsigned short powerDenial);
+
+  /**
+   * Notify CLIR from received Cdma-Info-Record.
+   * See 'ANNEX 1 Country-Specific Record Type for Japan' in T53.
+   * http://www.arib.or.jp/english/html/overview/doc/T53v6_5_pdf/5_ANNEX_v6_5.pdf
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param cause
+   *        Reason code. (8-bit binary)
+   *        See Table A 1.1-1 in T53.
+   */
+  void notifyCdmaInfoRecClir(in unsigned long clientId,
+                             in unsigned short cause);
+
+  /**
+   * Notify Audio Control from received Cdma-Info-Record.
+   *
+   * Note: No information from ARIB about Audio Control.
+   *       It seems obsolete according to ANNEX 1 in T53.
+   *       upLink/downLink are 'byte' value according to ril.h.
+   *       Treat them as 'signed short' to preserve the flexibility when needed.
+   *
+   * @param clientId
+   *        The ID of radioInterface where this info is notified from.
+   * @param upLink
+   * @param downLink
+   */
+  void notifyCdmaInfoRecAudioControl(in unsigned long clientId,
+                                     in short upLink,
+                                     in short downLink);
 };
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -391,23 +391,16 @@ XPCOMUtils.defineLazyGetter(this, "gMess
           this._resendQueuedTargetMessage();
           break;
         case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
           this._shutdown();
           break;
       }
     },
 
-    sendMobileConnectionMessage: function(message, clientId, data) {
-      this._sendTargetMessage("mobileconnection", message, {
-        clientId: clientId,
-        data: data
-      });
-    },
-
     sendIccMessage: function(message, clientId, data) {
       this._sendTargetMessage("icc", message, {
         clientId: clientId,
         data: data
       });
     }
   };
 });
@@ -1158,17 +1151,17 @@ DataConnectionHandler.prototype = {
       default:
         return Ci.nsINetworkInterface.NETWORK_TYPE_UNKNOWN;
      }
   },
 
   _compareDataCallOptions: function(dataCall, newDataCall) {
     return dataCall.apnProfile.apn == newDataCall.apn &&
            dataCall.apnProfile.user == newDataCall.user &&
-           dataCall.apnProfile.password == newDataCall.password &&
+           dataCall.apnProfile.password == newDataCall.passwd &&
            dataCall.chappap == newDataCall.chappap &&
            dataCall.pdptype == newDataCall.pdptype;
   },
 
   _deliverDataCallMessage: function(name, args) {
     for (let i = 0; i < this._dataCalls.length; i++) {
       let datacall = this._dataCalls[i];
       // Send message only to the DataCall that matches the data call options.
@@ -2086,18 +2079,17 @@ RadioInterface.prototype = {
         break;
       case "stkcommand":
         this.handleStkProactiveCommand(message);
         break;
       case "stksessionend":
         gMessageManager.sendIccMessage("RIL:StkSessionEnd", this.clientId, null);
         break;
       case "cdma-info-rec-received":
-        if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(message));
-        gSystemMessenger.broadcastMessage("cdma-info-rec-received", message);
+        this.handleCdmaInformationRecords(message.records);
         break;
       default:
         throw new Error("Don't know about this message type: " +
                         message.rilMessageType);
     }
   },
 
   /**
@@ -2915,16 +2907,109 @@ RadioInterface.prototype = {
                              hasEtwsInfo,
                              (hasEtwsInfo)
                                ? this._convertCbEtwsWarningType(etwsInfo.warningType)
                                : Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID,
                              hasEtwsInfo ? etwsInfo.emergencyUserAlert : false,
                              hasEtwsInfo ? etwsInfo.popup : false);
   },
 
+  handleCdmaInformationRecords: function(aRecords) {
+    if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(aRecords));
+
+    let clientId = this.clientId;
+
+    aRecords.forEach(function(aRecord) {
+      if (aRecord.display) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecDisplay(clientId, aRecord.display);
+        return;
+      }
+
+      if (aRecord.calledNumber) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecCalledPartyNumber(clientId,
+                                              aRecord.calledNumber.type,
+                                              aRecord.calledNumber.plan,
+                                              aRecord.calledNumber.number,
+                                              aRecord.calledNumber.pi,
+                                              aRecord.calledNumber.si);
+        return;
+      }
+
+      if (aRecord.callingNumber) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecCallingPartyNumber(clientId,
+                                               aRecord.callingNumber.type,
+                                               aRecord.callingNumber.plan,
+                                               aRecord.callingNumber.number,
+                                               aRecord.callingNumber.pi,
+                                               aRecord.callingNumber.si);
+        return;
+      }
+
+      if (aRecord.connectedNumber) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecConnectedPartyNumber(clientId,
+                                                 aRecord.connectedNumber.type,
+                                                 aRecord.connectedNumber.plan,
+                                                 aRecord.connectedNumber.number,
+                                                 aRecord.connectedNumber.pi,
+                                                 aRecord.connectedNumber.si);
+        return;
+      }
+
+      if (aRecord.signal) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecSignal(clientId,
+                                   aRecord.signal.type,
+                                   aRecord.signal.alertPitch,
+                                   aRecord.signal.signal);
+        return;
+      }
+
+      if (aRecord.redirect) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecRedirectingNumber(clientId,
+                                              aRecord.redirect.type,
+                                              aRecord.redirect.plan,
+                                              aRecord.redirect.number,
+                                              aRecord.redirect.pi,
+                                              aRecord.redirect.si,
+                                              aRecord.redirect.reason);
+        return;
+      }
+
+      if (aRecord.lineControl) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecLineControl(clientId,
+                                        aRecord.lineControl.polarityIncluded,
+                                        aRecord.lineControl.toggle,
+                                        aRecord.lineControl.reverse,
+                                        aRecord.lineControl.powerDenial);
+        return;
+      }
+
+      if (aRecord.clirCause) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecClir(clientId,
+                                 aRecord.clirCause);
+        return;
+      }
+
+      if (aRecord.audioControl) {
+        gMobileConnectionService
+          .notifyCdmaInfoRecAudioControl(clientId,
+                                         aRecord.audioControl.upLink,
+                                         aRecord.audioControl.downLink);
+        return;
+      }
+    });
+  },
+
   // nsIObserver
 
   observe: function(subject, topic, data) {
     switch (topic) {
       case kMozSettingsChangedObserverTopic:
         if ("wrappedJSObject" in subject) {
           subject = subject.wrappedJSObject;
         }
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -6915,19 +6915,20 @@ RilObject.prototype[UNSOLICITED_CDMA_OTA
     CDMA_OTA_PROVISION_STATUS_TO_GECKO[this.context.Buf.readInt32List()[0]];
   if (!status) {
     return;
   }
   this.sendChromeMessage({rilMessageType: "otastatuschange",
                           status: status});
 };
 RilObject.prototype[UNSOLICITED_CDMA_INFO_REC] = function UNSOLICITED_CDMA_INFO_REC(length) {
-  let record = this.context.CdmaPDUHelper.decodeInformationRecord();
-  record.rilMessageType = "cdma-info-rec-received";
-  this.sendChromeMessage(record);
+  this.sendChromeMessage({
+    rilMessageType: "cdma-info-rec-received",
+    records: this.context.CdmaPDUHelper.decodeInformationRecord()
+  });
 };
 RilObject.prototype[UNSOLICITED_OEM_HOOK_RAW] = null;
 RilObject.prototype[UNSOLICITED_RINGBACK_TONE] = null;
 RilObject.prototype[UNSOLICITED_RESEND_INCALL_MUTE] = null;
 RilObject.prototype[UNSOLICITED_CDMA_SUBSCRIPTION_SOURCE_CHANGED] = null;
 RilObject.prototype[UNSOLICITED_CDMA_PRL_CHANGED] = function UNSOLICITED_CDMA_PRL_CHANGED(length) {
   let version = this.context.Buf.readInt32List()[0];
   if (version !== this.iccInfo.prlVersion) {
@@ -9982,28 +9983,31 @@ CdmaPDUHelperObject.prototype = {
     return result;
   },
 
   /**
    * Decode information record parcel.
    */
   decodeInformationRecord: function() {
     let Buf = this.context.Buf;
-    let record = {};
+    let records = [];
     let numOfRecords = Buf.readInt32();
 
     let type;
+    let record;
     for (let i = 0; i < numOfRecords; i++) {
+      record = {};
       type = Buf.readInt32();
 
       switch (type) {
         /*
          * Every type is encaped by ril, except extended display
          */
         case PDU_CDMA_INFO_REC_TYPE_DISPLAY:
+        case PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY:
           record.display = Buf.readString();
           break;
         case PDU_CDMA_INFO_REC_TYPE_CALLED_PARTY_NUMBER:
           record.calledNumber = {};
           record.calledNumber.number = Buf.readString();
           record.calledNumber.type = Buf.readInt32();
           record.calledNumber.plan = Buf.readInt32();
           record.calledNumber.pi = Buf.readInt32();
@@ -10022,17 +10026,20 @@ CdmaPDUHelperObject.prototype = {
           record.connectedNumber.number = Buf.readString();
           record.connectedNumber.type = Buf.readInt32();
           record.connectedNumber.plan = Buf.readInt32();
           record.connectedNumber.pi = Buf.readInt32();
           record.connectedNumber.si = Buf.readInt32();
           break;
         case PDU_CDMA_INFO_REC_TYPE_SIGNAL:
           record.signal = {};
-          record.signal.present = Buf.readInt32();
+          if (!Buf.readInt32()) { // Non-zero if signal is present.
+            Buf.seekIncoming(3 * Buf.UINT32_SIZE);
+            continue;
+          }
           record.signal.type = Buf.readInt32();
           record.signal.alertPitch = Buf.readInt32();
           record.signal.signal = Buf.readInt32();
           break;
         case PDU_CDMA_INFO_REC_TYPE_REDIRECTING_NUMBER:
           record.redirect = {};
           record.redirect.number = Buf.readString();
           record.redirect.type = Buf.readInt32();
@@ -10040,64 +10047,37 @@ CdmaPDUHelperObject.prototype = {
           record.redirect.pi = Buf.readInt32();
           record.redirect.si = Buf.readInt32();
           record.redirect.reason = Buf.readInt32();
           break;
         case PDU_CDMA_INFO_REC_TYPE_LINE_CONTROL:
           record.lineControl = {};
           record.lineControl.polarityIncluded = Buf.readInt32();
           record.lineControl.toggle = Buf.readInt32();
-          record.lineControl.recerse = Buf.readInt32();
+          record.lineControl.reverse = Buf.readInt32();
           record.lineControl.powerDenial = Buf.readInt32();
           break;
-        case PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY:
-          let length = Buf.readInt32();
-          /*
-           * Extended display is still in format defined in
-           * C.S0005-F v1.0, 3.7.5.16
-           */
-          record.extendedDisplay = {};
-
-          let headerByte = Buf.readInt32();
-          length--;
-          // Based on spec, headerByte must be 0x80 now
-          record.extendedDisplay.indicator = (headerByte >> 7);
-          record.extendedDisplay.type = (headerByte & 0x7F);
-          record.extendedDisplay.records = [];
-
-          while (length > 0) {
-            let display = {};
-
-            display.tag = Buf.readInt32();
-            length--;
-            if (display.tag !== INFO_REC_EXTENDED_DISPLAY_BLANK &&
-                display.tag !== INFO_REC_EXTENDED_DISPLAY_SKIP) {
-              display.content = Buf.readString();
-              length -= (display.content.length + 1);
-            }
-
-            record.extendedDisplay.records.push(display);
-          }
-          break;
         case PDU_CDMA_INFO_REC_TYPE_T53_CLIR:
-          record.cause = Buf.readInt32();
+          record.clirCause = Buf.readInt32();
           break;
         case PDU_CDMA_INFO_REC_TYPE_T53_AUDIO_CONTROL:
           record.audioControl = {};
           record.audioControl.upLink = Buf.readInt32();
           record.audioControl.downLink = Buf.readInt32();
           break;
         case PDU_CDMA_INFO_REC_TYPE_T53_RELEASE:
           // Fall through
         default:
-          throw new Error("UNSOLICITED_CDMA_INFO_REC(), Unsupported information record type " + record.type + "\n");
-      }
-    }
-
-    return record;
+          throw new Error("UNSOLICITED_CDMA_INFO_REC(), Unsupported information record type " + type + "\n");
+      }
+
+      records.push(record);
+    }
+
+    return records;
   }
 };
 
 /**
  * Helper for processing ICC PDUs.
  */
 function ICCPDUHelperObject(aContext) {
   this.context = aContext;
--- a/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js
+++ b/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js
@@ -31,16 +31,20 @@ function newWorkerWithParcel(parcelBuf) 
   context.Buf.readUint16 = function() {
     return buf[index++];
   };
 
   context.Buf.readInt32 = function() {
     return buf[index++];
   };
 
+  context.Buf.seekIncoming = function(offset) {
+    index += offset / context.Buf.UINT32_SIZE;
+  };
+
   return worker;
 }
 
 // Test CDMA information record decoder.
 
 /**
  * Verify decoder for type DISPLAY
  */
@@ -48,76 +52,183 @@ add_test(function test_display() {
   let worker = newWorkerWithParcel([
                 0x01, // one inforemation record
                 0x00, // type: display
                 0x09, // length: 9
                 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
                 0x6F, 0x00]);
   let context = worker.ContextPool._contexts[0];
   let helper = context.CdmaPDUHelper;
-  let record = helper.decodeInformationRecord();
+  let records = helper.decodeInformationRecord();
 
-  do_check_eq(record.display, "Test Info");
+  do_check_eq(records[0].display, "Test Info");
 
   run_next_test();
 });
 
 /**
  * Verify decoder for type EXTENDED DISPLAY
  */
 add_test(function test_extended_display() {
   let worker = newWorkerWithParcel([
                 0x01, // one inforemation record
                 0x07, // type: extended display
-                0x0E, // length: 14
-                0x80, // header byte
-                0x80, // Blank
-                0x81, // Skip
-                0x9B, // Text
-                0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E,
-                0x66, 0x6F, 0x00]);
+                0x12, // length: 18
+                0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74,
+                0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E,
+                0x66, 0x6F, 0x00, 0x00]);
   let context = worker.ContextPool._contexts[0];
   let helper = context.CdmaPDUHelper;
-  let record = helper.decodeInformationRecord();
+  let records = helper.decodeInformationRecord();
 
-  do_check_eq(record.extendedDisplay.indicator, 1);
-  do_check_eq(record.extendedDisplay.type, 0);
-  do_check_eq(record.extendedDisplay.records.length, 3);
-  do_check_eq(record.extendedDisplay.records[0].tag, 0x80);
-  do_check_eq(record.extendedDisplay.records[1].tag, 0x81);
-  do_check_eq(record.extendedDisplay.records[2].tag, 0x9B);
-  do_check_eq(record.extendedDisplay.records[2].content, "Test Info");
+  do_check_eq(records[0].display, "Test Extended Info");
 
   run_next_test();
 });
+
 /**
  * Verify decoder for mixed type
  */
 add_test(function test_mixed() {
   let worker = newWorkerWithParcel([
                 0x02, // two inforemation record
                 0x00, // type: display
-                0x09, // length: 9
+                0x0B, // length: 11
                 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
-                0x6F, 0x00,
+                0x6F, 0x20, 0x31, 0x00,
                 0x07, // type: extended display
-                0x0E, // length: 14
-                0x80, // header byte
-                0x80, // Blank
-                0x81, // Skip
-                0x9B, // Text
-                0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E,
-                0x66, 0x6F, 0x00]);
+                0x0B, // length: 11
+                0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
+                0x6F, 0x20, 0x32, 0x00]);
   let context = worker.ContextPool._contexts[0];
   let helper = context.CdmaPDUHelper;
-  let record = helper.decodeInformationRecord();
+  let records = helper.decodeInformationRecord();
+
+  do_check_eq(records[0].display, "Test Info 1");
+  do_check_eq(records[1].display, "Test Info 2");
+
+  run_next_test();
+});
 
-  do_check_eq(record.display, "Test Info");
-  do_check_eq(record.extendedDisplay.indicator, 1);
-  do_check_eq(record.extendedDisplay.type, 0);
-  do_check_eq(record.extendedDisplay.records.length, 3);
-  do_check_eq(record.extendedDisplay.records[0].tag, 0x80);
-  do_check_eq(record.extendedDisplay.records[1].tag, 0x81);
-  do_check_eq(record.extendedDisplay.records[2].tag, 0x9B);
-  do_check_eq(record.extendedDisplay.records[2].content, "Test Info");
+/**
+ * Verify decoder for multiple types
+ */
+add_test(function test_multiple() {
+  let worker = newWorkerWithParcel([
+                0x02, // two inforemation record
+                0x00, // type: display
+                0x0B, // length: 11
+                0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
+                0x6F, 0x20, 0x31, 0x00,
+                0x00, // type: display
+                0x0B, // length: 11
+                0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
+                0x6F, 0x20, 0x32, 0x00]);
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.CdmaPDUHelper;
+  let records = helper.decodeInformationRecord();
+
+  do_check_eq(records[0].display, "Test Info 1");
+  do_check_eq(records[1].display, "Test Info 2");
+
+  run_next_test();
+});
+
+/**
+ * Verify decoder for Signal Type
+ */
+add_test(function test_signal() {
+  let worker = newWorkerWithParcel([
+                0x01,   // one inforemation record
+                0x04,   // type: signal
+                0x01,   // isPresent: non-zero
+                0x00,   // signalType: Tone signal (00)
+                0x01,   // alertPitch: High pitch
+                0x03]); // signal: Abbreviated intercept (000011)
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.CdmaPDUHelper;
+  let records = helper.decodeInformationRecord();
+
+  do_check_eq(records[0].signal.type, 0x00);
+  do_check_eq(records[0].signal.alertPitch, 0x01);
+  do_check_eq(records[0].signal.signal, 0x03);
 
   run_next_test();
 });
+
+/**
+ * Verify decoder for Signal Type for Not Presented
+ */
+add_test(function test_signal_not_present() {
+  let worker = newWorkerWithParcel([
+                0x01,   // one inforemation record
+                0x04,   // type: signal
+                0x00,   // isPresent: zero
+                0x00,   // signalType: Tone signal (00)
+                0x01,   // alertPitch: High pitch
+                0x03]); // signal: Abbreviated intercept (000011)
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.CdmaPDUHelper;
+  let records = helper.decodeInformationRecord();
+
+  do_check_eq(records.length, 0);
+
+  run_next_test();
+});
+
+/**
+ * Verify decoder for Line Control
+ */
+add_test(function test_line_control() {
+  let worker = newWorkerWithParcel([
+                0x01,   // one inforemation record
+                0x06,   // type: line control
+                0x01,   // polarity included
+                0x00,   // not toggled
+                0x01,   // reversed
+                0xFF]); // Power denial timeout: 255 * 5 ms
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.CdmaPDUHelper;
+  let records = helper.decodeInformationRecord();
+
+  do_check_eq(records[0].lineControl.polarityIncluded, 1);
+  do_check_eq(records[0].lineControl.toggle, 0);
+  do_check_eq(records[0].lineControl.reverse, 1);
+  do_check_eq(records[0].lineControl.powerDenial, 255);
+
+  run_next_test();
+});
+
+/**
+ * Verify decoder for CLIR Cause
+ */
+add_test(function test_clir() {
+  let worker = newWorkerWithParcel([
+                0x01,   // one inforemation record
+                0x08,   // type: clir
+                0x01]); // cause: Rejected by user
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.CdmaPDUHelper;
+  let records = helper.decodeInformationRecord();
+
+  do_check_eq(records[0].clirCause, 1);
+
+  run_next_test();
+});
+
+/**
+ * Verify decoder for Audio Control
+ */
+add_test(function test_clir() {
+  let worker = newWorkerWithParcel([
+                0x01,   // one inforemation record
+                0x0A,   // type: audio control
+                0x01,   // uplink
+                0xFF]); // downlink
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.CdmaPDUHelper;
+  let records = helper.decodeInformationRecord();
+
+  do_check_eq(records[0].audioControl.upLink, 1);
+  do_check_eq(records[0].audioControl.downLink, 255);
+
+  run_next_test();
+});
--- a/dom/wifi/WifiCertService.cpp
+++ b/dom/wifi/WifiCertService.cpp
@@ -222,36 +222,25 @@ private:
 
 NS_IMPL_ISUPPORTS(WifiCertService, nsIWifiCertService)
 
 NS_IMETHODIMP
 WifiCertService::Start(nsIWifiEventListener* aListener)
 {
   MOZ_ASSERT(aListener);
 
-  nsresult rv = NS_NewThread(getter_AddRefs(mRequestThread));
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Certn't create wifi control thread");
-    Shutdown();
-    return NS_ERROR_FAILURE;
-  }
-
   mListener = aListener;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WifiCertService::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  if (mRequestThread) {
-    mRequestThread->Shutdown();
-    mRequestThread = nullptr;
-  }
 
   mListener = nullptr;
 
   return NS_OK;
 }
 
 void
 WifiCertService::DispatchResult(const WifiCertServiceResultOptions& aOptions)
--- a/dom/wifi/WifiCertService.h
+++ b/dom/wifi/WifiCertService.h
@@ -22,16 +22,15 @@ public:
 
   static already_AddRefed<WifiCertService>
   FactoryCreate();
   void DispatchResult(const mozilla::dom::WifiCertServiceResultOptions& aOptions);
 
 private:
   WifiCertService();
   ~WifiCertService();
-  nsCOMPtr<nsIThread> mRequestThread;
   nsCOMPtr<nsIWifiEventListener> mListener;
 };
 
 } // namespce dom
 } // namespace mozilla
 
 #endif // WifiCertService_h
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1854,17 +1854,17 @@ function WifiWorker() {
         ("password" in net && net.password) ||
         ("wep_key0" in net && net.wep_key0)) {
       password = "*";
     }
 
     var pub = new Network(ssid, security, password);
     if (net.identity)
       pub.identity = dequote(net.identity);
-    if (net.netId)
+    if ("netId" in net)
       pub.known = true;
     if (net.scan_ssid === 1)
       pub.hidden = true;
     if ("ca_cert" in net && net.ca_cert &&
         net.ca_cert.indexOf("keystore://WIFI_SERVERCERT_" === 0)) {
       pub.serverCertificate = net.ca_cert.substr(27);
     }
     if(net.subject_match) {
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -2755,17 +2755,17 @@ public class BrowserApp extends GeckoApp
             }
         }
 
         // Disable share menuitem for about:, chrome:, file:, and resource: URIs
         final boolean shareEnabled = RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_SHARE);
         share.setVisible(shareEnabled);
         share.setEnabled(StringUtils.isShareableUrl(url) && shareEnabled);
         MenuUtils.safeSetEnabled(aMenu, R.id.apps, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_APPS));
-        MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSIONS));
+        MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSION));
         MenuUtils.safeSetEnabled(aMenu, R.id.downloads, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_DOWNLOADS));
 
         // NOTE: Use MenuUtils.safeSetEnabled because some actions might
         // be on the BrowserToolbar context menu.
         if (Versions.feature11Plus) {
             MenuUtils.safeSetEnabled(aMenu, R.id.page, !isAboutHome(tab));
         }
         MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, tab.hasFeeds());
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -76,16 +76,17 @@ import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.location.Location;
 import android.location.LocationListener;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.StrictMode;
 import android.provider.ContactsContract;
 import android.provider.MediaStore.Images.Media;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Base64;
@@ -973,16 +974,22 @@ public abstract class GeckoApp
 
                 while((byteRead = is.read(buf)) != -1) {
                     os.write(buf, 0, byteRead);
                 }
                 byte[] imgBuffer = os.toByteArray();
                 image = BitmapUtils.decodeByteArray(imgBuffer);
             }
             if (image != null) {
+                // Some devices don't have a DCIM folder and the Media.insertImage call will fail.
+                File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+                if (!dcimDir.mkdirs() && !dcimDir.isDirectory()) {
+                    Toast.makeText((Context) this, R.string.set_image_path_fail, Toast.LENGTH_SHORT).show();
+                    return;
+                }
                 String path = Media.insertImage(getContentResolver(),image, null, null);
                 if (path == null) {
                     Toast.makeText((Context) this, R.string.set_image_path_fail, Toast.LENGTH_SHORT).show();
                     return;
                 }
                 final Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
                 intent.addCategory(Intent.CATEGORY_DEFAULT);
                 intent.setData(Uri.parse(path));
--- a/mobile/android/base/RestrictedProfiles.java
+++ b/mobile/android/base/RestrictedProfiles.java
@@ -50,24 +50,26 @@ public class RestrictedProfiles {
     }};
 
     /* This is a list of things we can restrict you from doing. Some of these are reflected in Android UserManager constants.
      * Others are specific to us.
      * These constants should be in sync with the ones from toolkit/components/parentalcontrols/nsIParentalControlServices.idl
      */
     public static enum Restriction {
         DISALLOW_DOWNLOADS(1, "no_download_files"),
-        DISALLOW_INSTALL_EXTENSIONS(2, "no_install_extensions"),
+        DISALLOW_INSTALL_EXTENSION(2, "no_install_extensions"),
         DISALLOW_INSTALL_APPS(3, "no_install_apps"), // UserManager.DISALLOW_INSTALL_APPS
         DISALLOW_BROWSE_FILES(4, "no_browse_files"),
         DISALLOW_SHARE(5, "no_share"),
         DISALLOW_BOOKMARK(6, "no_bookmark"),
         DISALLOW_ADD_CONTACTS(7, "no_add_contacts"),
         DISALLOW_SET_IMAGE(8, "no_set_image"),
-        DISALLOW_MODIFY_ACCOUNTS(9, "no_modify_accounts"); // UserManager.DISALLOW_MODIFY_ACCOUNTS
+        DISALLOW_MODIFY_ACCOUNTS(9, "no_modify_accounts"), // UserManager.DISALLOW_MODIFY_ACCOUNTS
+        DISALLOW_REMOTE_DEBUGGING(10, "no_remote_debugging"),
+        DISALLOW_IMPORT_SETTINGS(11, "no_import_settings");
 
         public final int id;
         public final String name;
 
         private Restriction(final int id, final String name) {
             this.id = id;
             this.name = name;
         }
--- a/mobile/android/base/home/HomePagerTabStrip.java
+++ b/mobile/android/base/home/HomePagerTabStrip.java
@@ -5,17 +5,20 @@
 
 package org.mozilla.gecko.home;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.animation.BounceAnimator;
 import org.mozilla.gecko.animation.BounceAnimator.Attributes;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.support.v4.view.PagerTabStrip;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewTreeObserver;
 
 import com.nineoldandroids.animation.AnimatorSet;
 import com.nineoldandroids.animation.ObjectAnimator;
 import com.nineoldandroids.animation.ValueAnimator;
@@ -32,40 +35,58 @@ class HomePagerTabStrip extends PagerTab
     private static final int ANIMATION_DELAY_MS = 250;
     private static final int ALPHA_MS = 10;
     private static final int BOUNCE1_MS = 350;
     private static final int BOUNCE2_MS = 200;
     private static final int BOUNCE3_MS = 100;
     private static final int BOUNCE4_MS = 100;
     private static final int INIT_OFFSET = 100;
 
+    private final Paint shadowPaint;
+    private final int shadowSize;
+
     public HomePagerTabStrip(Context context) {
-        super(context);
+        this(context, null);
     }
 
     public HomePagerTabStrip(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HomePagerTabStrip);
         int color = a.getColor(R.styleable.HomePagerTabStrip_tabIndicatorColor, 0x00);
         a.recycle();
 
         setTabIndicatorColor(color);
 
+        final Resources res = getResources();
+        shadowSize = res.getDimensionPixelSize(R.dimen.tabs_strip_shadow_size);
+
+        shadowPaint = new Paint();
+        shadowPaint.setColor(res.getColor(R.color.url_bar_shadow));
+        shadowPaint.setStrokeWidth(0.0f);
+
         getViewTreeObserver().addOnPreDrawListener(new PreDrawListener());
     }
 
     @Override
     public int getPaddingBottom() {
         // PagerTabStrip enforces a minimum bottom padding of 6dp which causes
         // misalignments when using 'center_vertical' gravity. Force padding bottom
         // to 0dp so that children are properly centered.
         return 0;
     }
 
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+
+        final int height = getHeight();
+        canvas.drawRect(0, height - shadowSize, getWidth(), height, shadowPaint);
+    }
+
     private void animateTitles() {
         final View prevTextView = getChildAt(0);
         final View nextTextView = getChildAt(getChildCount() - 1);
 
         if (prevTextView == null || nextTextView == null) {
             return;
         }
 
--- a/mobile/android/base/home/ReadingListRow.java
+++ b/mobile/android/base/home/ReadingListRow.java
@@ -3,40 +3,85 @@
  * 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/. */
 
 package org.mozilla.gecko.home;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
 import org.mozilla.gecko.home.TwoLinePageRow;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
 import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class ReadingListRow extends LinearLayout {
+
+    private final Resources resources;
 
-public class ReadingListRow extends TwoLinePageRow {
+    private final TextView title;
+    private final TextView excerpt;
+    private final TextView readTime;
+
+    // Average reading speed in words per minute.
+    private static final int AVERAGE_READING_SPEED = 250;
+
+    // Length of average word.
+    private static final float AVERAGE_WORD_LENGTH = 5.1f;
+
 
     public ReadingListRow(Context context) {
         this(context, null);
     }
 
     public ReadingListRow(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        LayoutInflater.from(context).inflate(R.layout.reading_list_row_view, this);
+
+        setOrientation(LinearLayout.VERTICAL);
+
+        resources = context.getResources();
+
+        title = (TextView) findViewById(R.id.title);
+        excerpt = (TextView) findViewById(R.id.excerpt);
+        readTime = (TextView) findViewById(R.id.read_time);
     }
 
-    @Override
-    protected void updateDisplayedUrl() {
-        String pageUrl = getUrl();
+    public void updateFromCursor(Cursor cursor) {
+        if (cursor == null) {
+            return;
+        }
 
-        boolean isPrivate = Tabs.getInstance().getSelectedTab().isPrivate();
-        Tab tab = Tabs.getInstance().getFirstReaderTabForUrl(pageUrl, isPrivate);
+        final int titleIndex = cursor.getColumnIndexOrThrow(ReadingListItems.TITLE);
+        title.setText(cursor.getString(titleIndex));
 
-        if (tab != null) {
-            setUrl(R.string.switch_to_tab);
-            setSwitchToTabIcon(R.drawable.ic_url_bar_tab);
+        final int excerptIndex = cursor.getColumnIndexOrThrow(ReadingListItems.EXCERPT);
+        excerpt.setText(cursor.getString(excerptIndex));
+
+        final int lengthIndex = cursor.getColumnIndexOrThrow(ReadingListItems.LENGTH);
+        final int minutes = getEstimatedReadTime(cursor.getInt(lengthIndex));
+        if (minutes <= 60) {
+            readTime.setText(resources.getString(R.string.reading_list_time_minutes, minutes));
         } else {
-            setUrl(pageUrl);
-            setSwitchToTabIcon(NO_ICON);
+            readTime.setText(resources.getString(R.string.reading_list_time_over_an_hour));
         }
     }
 
+    /**
+     * Calculates the estimated time to read an article based on its length.
+     *
+     * @param length of the article (in characters)
+     * @return estimated time to read the article (in minutes)
+     */
+    private static int getEstimatedReadTime(int length) {
+        final int minutes = (int) Math.ceil((length / AVERAGE_WORD_LENGTH) / AVERAGE_READING_SPEED);
+
+        // Minimum of one minute.
+        return Math.max(minutes, 1);
+    }
 }
--- a/mobile/android/base/home/RemoteTabsPanel.java
+++ b/mobile/android/base/home/RemoteTabsPanel.java
@@ -1,17 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.home;
 
 import java.util.EnumMap;
-import java.util.HashMap;
 import java.util.Map;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.fxa.AccountLoader;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.login.State.Action;
@@ -47,20 +46,24 @@ public class RemoteTabsPanel extends Hom
 
     // The current fragment being shown to reflect the system account state. We
     // don't want to detach and re-attach panels unnecessarily, because that
     // causes flickering.
     private Fragment mCurrentFragment;
 
     // A lazily-populated cache of fragments corresponding to the possible
     // system account states. We don't want to re-create panels unnecessarily,
-    // because that can cause flickering. Be aware that null is a valid key; it
-    // corresponds to "no Account, neither Firefox nor Legacy Sync."
+    // because that can cause flickering. `null` is not a valid key.
     private final Map<Action, Fragment> mFragmentCache = new EnumMap<>(Action.class);
 
+    // The fragment that corresponds to the null action -- "no Account,
+    // neither Firefox nor Legacy Sync."
+    // Lazily populated.
+    private Fragment mFallbackFragment;
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         return inflater.inflate(R.layout.home_remote_tabs_panel, container, false);
     }
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
@@ -170,22 +173,30 @@ public class RemoteTabsPanel extends Hom
      * A null Account means there is no Account (Sync or Firefox) on the device.
      *
      * @param account
      *            Android Account (Sync or Firefox); may be null.
      */
     private Fragment getFragmentNeeded(Account account) {
         final Action actionNeeded = getActionNeeded(account);
 
-        // We use containsKey rather than get because null is a valid key.
-        if (!mFragmentCache.containsKey(actionNeeded)) {
-            final Fragment fragment = makeFragmentForAction(actionNeeded);
+        if (actionNeeded == null) {
+            if (mFallbackFragment == null) {
+                mFallbackFragment = makeFragmentForAction(null);
+            }
+            return mFallbackFragment;
+        }
+
+        Fragment fragment = mFragmentCache.get(actionNeeded);
+        if (fragment == null) {
+            fragment = makeFragmentForAction(actionNeeded);
             mFragmentCache.put(actionNeeded, fragment);
         }
-        return mFragmentCache.get(actionNeeded);
+
+        return fragment;
     }
 
     /**
      * Update the UI to reflect the given <code>Account</code> and its state.
      * <p>
      * A null Account means there is no Account (Sync or Firefox) on the device.
      *
      * @param account
--- a/mobile/android/base/home/TabMenuStrip.java
+++ b/mobile/android/base/home/TabMenuStrip.java
@@ -3,18 +3,20 @@
  * 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/. */
 
 package org.mozilla.gecko.home;
 
 import org.mozilla.gecko.R;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.HorizontalScrollView;
 import android.widget.LinearLayout;
@@ -30,26 +32,45 @@ public class TabMenuStrip extends Horizo
 
     // Offset between the selected tab title and the edge of the screen,
     // except for the first and last tab in the tab strip.
     private static final int TITLE_OFFSET_DIPS = 24;
 
     private final int titleOffset;
     private final TabMenuStripLayout layout;
 
+    private final Paint shadowPaint;
+    private final int shadowSize;
+
     public TabMenuStrip(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         // Disable the scroll bar.
         setHorizontalScrollBarEnabled(false);
 
-        titleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+        final Resources res = getResources();
+
+        titleOffset = (int) (TITLE_OFFSET_DIPS * res.getDisplayMetrics().density);
 
         layout = new TabMenuStripLayout(context, attrs);
         addView(layout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+        shadowSize = res.getDimensionPixelSize(R.dimen.tabs_strip_shadow_size);
+
+        shadowPaint = new Paint();
+        shadowPaint.setColor(res.getColor(R.color.url_bar_shadow));
+        shadowPaint.setStrokeWidth(0.0f);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+
+        final int height = getHeight();
+        canvas.drawRect(0, height - shadowSize, getWidth(), height, shadowPaint);
     }
 
     @Override
     public void onAddPagerView(String title) {
         layout.onAddPagerView(title);
     }
 
     @Override
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -359,16 +359,22 @@ size. -->
 <!ENTITY site_settings_cancel       "Cancel">
 <!ENTITY site_settings_clear        "Clear">
 <!ENTITY site_settings_no_settings  "There are no settings to clear.">
 
 <!ENTITY reading_list_added "Page added to your Reading List">
 <!ENTITY reading_list_failed "Failed to add page to your Reading List">
 <!ENTITY reading_list_duplicate "Page already in your Reading List">
 
+<!-- Localization note (reading_list_time_minutes) : This string is used in the "Reading List"
+     panel on the home page to give the user an estimate of how many minutes it will take to
+     read an article. The word "minute" should be abbreviated if possible. -->
+<!ENTITY reading_list_time_minutes "&formatD;min">
+<!ENTITY reading_list_time_over_an_hour "Over an hour">
+
 <!-- Localization note : These strings are used as alternate text for accessibility.
      They are not visible in the UI. -->
 <!ENTITY page_action_dropmarker_description "Additional Actions">
 
 <!ENTITY masterpassword_create_title "Create Master Password">
 <!ENTITY masterpassword_remove_title "Remove Master Password">
 <!ENTITY masterpassword_password "Password">
 <!ENTITY masterpassword_confirm "Confirm password">
--- a/mobile/android/base/preferences/AndroidImportPreference.java
+++ b/mobile/android/base/preferences/AndroidImportPreference.java
@@ -2,29 +2,41 @@
  * 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/. */
 
 package org.mozilla.gecko.preferences;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.util.ThreadUtils;
+import org.mozilla.gecko.RestrictedProfiles;
+import org.mozilla.gecko.RestrictedProfiles.Restriction;
 
 import java.util.Set;
 
 import android.app.ProgressDialog;
 import android.content.Context;
+import android.preference.Preference;
 import android.util.AttributeSet;
 import android.util.Log;
 
 class AndroidImportPreference extends MultiPrefMultiChoicePreference {
     private static final String LOGTAG = "AndroidImport";
+    public static final String PREF_KEY = "android.not_a_preference.import_android";
     private static final String PREF_KEY_PREFIX = "import_android.data.";
     private final Context mContext;
 
+    public static class Handler implements GeckoPreferences.PrefHandler {
+        public boolean setupPref(Context context, Preference pref) {
+            return RestrictedProfiles.isAllowed(Restriction.DISALLOW_IMPORT_SETTINGS);
+        }
+
+        public void onChange(Context context, Preference pref, Object newValue) { }
+    }
+
     public AndroidImportPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
     }
 
     @Override
     protected void onDialogClosed(boolean positiveResult) {
         super.onDialogClosed(positiveResult);
--- a/mobile/android/base/preferences/ClearOnShutdownPref.java
+++ b/mobile/android/base/preferences/ClearOnShutdownPref.java
@@ -14,22 +14,23 @@ import org.mozilla.gecko.util.PrefUtils;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.preference.Preference;
 
 public class ClearOnShutdownPref implements GeckoPreferences.PrefHandler {
     public static final String PREF = GeckoPreferences.NON_PREF_PREFIX + "history.clear_on_exit";
 
     @Override
-    public void setupPref(Context context, Preference pref) {
+    public boolean setupPref(Context context, Preference pref) {
         // The pref is initialized asynchronously. Read the pref explicitly
         // here to make sure we have the data.
         final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
         final Set<String> clearItems = PrefUtils.getStringSet(prefs, PREF, new HashSet<String>());
         ((ListCheckboxPreference) pref).setChecked(clearItems.size() > 0);
+        return true;
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public void onChange(Context context, Preference pref, Object newValue) {
         final Set<String> vals = (Set<String>) newValue;
         ((ListCheckboxPreference) pref).setChecked(vals.size() > 0);
     }
--- a/mobile/android/base/preferences/GeckoPreferences.java
+++ b/mobile/android/base/preferences/GeckoPreferences.java
@@ -695,16 +695,22 @@ OnSharedPreferenceChangeListener
                     continue;
                 } else if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED &&
                            (PREFS_GEO_REPORTING.equals(key) ||
                             PREFS_GEO_LEARN_MORE.equals(key))) {
                     preferences.removePreference(pref);
                     i--;
                     continue;
                 } else if (PREFS_DEVTOOLS_REMOTE_ENABLED.equals(key)) {
+                    if (!RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_REMOTE_DEBUGGING)) {
+                        preferences.removePreference(pref);
+                        i--;
+                        continue;
+                    }
+
                     final Context thisContext = this;
                     pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                         @Override
                         public boolean onPreferenceClick(Preference preference) {
                             // Display toast to remind setting up tcp forwarding.
                             if (((CheckBoxPreference) preference).isChecked()) {
                                 Toast.makeText(thisContext, R.string.devtools_remote_debugging_forward, Toast.LENGTH_SHORT).show();
                             }
@@ -739,17 +745,21 @@ OnSharedPreferenceChangeListener
                 } else if (PREFS_DISPLAY_TITLEBAR_MODE.equals(key) &&
                            NewTabletUI.isEnabled(this)) {
                     // New tablet always shows URLS, not titles.
                     preferences.removePreference(pref);
                     i--;
                     continue;
                 } else if (handlers.containsKey(key)) {
                     PrefHandler handler = handlers.get(key);
-                    handler.setupPref(this, pref);
+                    if (!handler.setupPref(this, pref)) {
+                        preferences.removePreference(pref);
+                        i--;
+                        continue;
+                    }
                 }
 
                 // Some Preference UI elements are not actually preferences,
                 // but they require a key to work correctly. For example,
                 // "Clear private data" requires a key for its state to be
                 // saved when the orientation changes. It uses the
                 // "android.not_a_preference.privacy.clear" key - which doesn't
                 // exist in Gecko - to satisfy this requirement.
@@ -1021,23 +1031,26 @@ OnSharedPreferenceChangeListener
         } else if (PREFS_SUGGESTED_SITES.equals(key)) {
             refreshSuggestedSites();
         } else if (PREFS_NEW_TABLET_UI.equals(key)) {
             Toast.makeText(this, R.string.new_tablet_restart, Toast.LENGTH_SHORT).show();
         }
     }
 
     public interface PrefHandler {
-        public void setupPref(Context context, Preference pref);
+        // Allows the pref to do any initialization it needs. Return false to have the pref removed
+        // from the prefs screen entirely.
+        public boolean setupPref(Context context, Preference pref);
         public void onChange(Context context, Preference pref, Object newValue);
     }
 
     @SuppressWarnings("serial")
     private final Map<String, PrefHandler> handlers = new HashMap<String, PrefHandler>() {{
         put(ClearOnShutdownPref.PREF, new ClearOnShutdownPref());
+        put(AndroidImportPreference.PREF_KEY, new AndroidImportPreference.Handler());
     }};
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final String prefName = preference.getKey();
         Log.i(LOGTAG, "Changed " + prefName + " = " + newValue);
 
         Telemetry.sendUIEvent(TelemetryContract.Event.EDIT, Method.SETTINGS, prefName);
--- a/mobile/android/base/resources/layout-large-v11/home_pager.xml
+++ b/mobile/android/base/resources/layout-large-v11/home_pager.xml
@@ -9,14 +9,14 @@
 <org.mozilla.gecko.home.HomePager xmlns:android="http://schemas.android.com/apk/res/android"
                                   xmlns:gecko="http://schemas.android.com/apk/res-auto"
                                   android:id="@+id/home_pager"
                                   android:layout_width="match_parent"
                                   android:layout_height="match_parent"
                                   android:background="@android:color/white">
 
     <org.mozilla.gecko.home.TabMenuStrip android:layout_width="match_parent"
-                                         android:layout_height="32dip"
+                                         android:layout_height="@dimen/tabs_strip_height"
                                          android:background="@color/background_light"
                                          android:layout_gravity="top"
                                          gecko:strip="@drawable/home_tab_menu_strip"/>
 
 </org.mozilla.gecko.home.HomePager>
--- a/mobile/android/base/resources/layout/home_pager.xml
+++ b/mobile/android/base/resources/layout/home_pager.xml
@@ -9,16 +9,16 @@
 <org.mozilla.gecko.home.HomePager xmlns:android="http://schemas.android.com/apk/res/android"
                                   xmlns:gecko="http://schemas.android.com/apk/res-auto"
                                   android:id="@+id/home_pager"
                                   android:layout_width="match_parent"
                                   android:layout_height="match_parent"
                                   android:background="@android:color/white">
 
     <org.mozilla.gecko.home.HomePagerTabStrip android:layout_width="match_parent"
-                                              android:layout_height="40dip"
+                                              android:layout_height="@dimen/tabs_strip_height"
                                               android:layout_gravity="top"
                                               android:gravity="center_vertical"
                                               android:background="@color/background_light"
                                               gecko:tabIndicatorColor="@color/text_color_highlight"
                                               android:textAppearance="@style/TextAppearance.Widget.HomePagerTabStrip"/>
 
 </org.mozilla.gecko.home.HomePager>
--- a/mobile/android/base/resources/layout/home_reading_list_panel.xml
+++ b/mobile/android/base/resources/layout/home_reading_list_panel.xml
@@ -11,10 +11,10 @@
     <ViewStub android:id="@+id/home_empty_view_stub"
               android:layout="@layout/home_empty_reading_panel"
               android:layout_width="match_parent"
               android:layout_height="match_parent"/>
 
     <org.mozilla.gecko.home.HomeListView android:id="@+id/list"
                                          style="@style/Widget.ReadingListView"
                                          android:layout_width="match_parent"
-                                         android:layout_height="wrap_content"/>
+                                         android:layout_height="match_parent"/>
 </LinearLayout>
--- a/mobile/android/base/resources/layout/reading_list_item_row.xml
+++ b/mobile/android/base/resources/layout/reading_list_item_row.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <org.mozilla.gecko.home.ReadingListRow xmlns:android="http://schemas.android.com/apk/res/android"
                                        style="@style/Widget.BookmarkItemView"
                                        android:layout_width="match_parent"
-                                       android:layout_height="@dimen/page_row_height"
-                                       android:minHeight="@dimen/page_row_height"/>
+                                       android:layout_height="wrap_content"
+                                       android:padding="10dp"/>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/reading_list_row_view.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dip"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            style="@style/Widget.ReadingListRow.Title" />
+
+        <TextView
+            android:id="@+id/read_time"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            style="@style/Widget.ReadingListRow.ReadTime" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/excerpt"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/Widget.ReadingListRow.Description" />
+
+</merge>
--- a/mobile/android/base/resources/values-land/styles.xml
+++ b/mobile/android/base/resources/values-land/styles.xml
@@ -66,14 +66,9 @@
     </style>
 
     <style name="TabsPanelItem.TextAppearance.Linkified.Resend">
         <item name="android:layout_height">match_parent</item>
         <item name="android:gravity">center</item>
         <item name="android:layout_gravity">center</item>
     </style>
 
-    <style name="Widget.Home.HomeList">
-        <item name="topDivider">true</item>
-        <item name="android:scrollbarStyle">outsideOverlay</item>
-    </style>
-
 </resources>
--- a/mobile/android/base/resources/values-v16/styles.xml
+++ b/mobile/android/base/resources/values-v16/styles.xml
@@ -12,16 +12,22 @@
     <style name="TextAppearance.Widget.Home.ItemTitle" parent="TextAppearance.Medium">
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
 
     <style name="TextAppearance.Widget.Home.PageTitle" parent="TextAppearance.Medium">
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
 
+    <style name="Widget.ReadingListRow.ReadTime">
+        <item name="android:textStyle">italic</item>
+        <item name="android:textColor">#FF9400</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
+    </style>
+
     <style name="OnboardStartTextAppearance.Subtext">
         <item name="android:textSize">18sp</item>
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
     <style name="TextAppearance.UrlBar.Title" parent="TextAppearance.Small">
         <item name="android:textSize">15sp</item>
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
--- a/mobile/android/base/resources/values-xlarge-land-v11/styles.xml
+++ b/mobile/android/base/resources/values-xlarge-land-v11/styles.xml
@@ -14,21 +14,16 @@
     <style name="Widget.TopSitesGridView" parent="Widget.GridView">
         <item name="android:paddingLeft">55dp</item>
         <item name="android:paddingRight">55dp</item>
         <item name="android:paddingBottom">30dp</item>
         <item name="android:horizontalSpacing">56dp</item>
         <item name="android:verticalSpacing">20dp</item>
     </style>
 
-    <style name="Widget.Home.HomeList">
-        <item name="android:scrollbarStyle">outsideOverlay</item>
-        <item name="topDivider">true</item>
-    </style>
-
     <!-- Tabs panel -->
     <style name="TabsPanelFrame.RemoteTabs" parent="TabsPanelFrameBase">
         <item name="android:paddingLeft">0dp</item>
         <item name="android:paddingRight">0dp</item>
     </style>
 
     <style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
         <item name="android:paddingTop">12dp</item>
--- a/mobile/android/base/resources/values-xlarge-v11/styles.xml
+++ b/mobile/android/base/resources/values-xlarge-v11/styles.xml
@@ -11,21 +11,16 @@
     -->
 
     <!-- TabWidget --> 
     <style name="TabWidget">
         <item name="android:layout_width">300dip</item>
         <item name="android:layout_height">48dip</item>
     </style>
 
-    <style name="Widget.Home.HomeList">
-        <item name="android:scrollbarStyle">outsideOverlay</item>
-        <item name="topDivider">true</item>
-    </style>
-
     <!-- Tabs panel -->
     <style name="TabsPanelFrame.RemoteTabs" parent="TabsPanelFrameBase">
         <item name="android:paddingLeft">212dp</item>
         <item name="android:paddingRight">212dp</item>
     </style>
 
     <style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
         <item name="android:paddingTop">30dp</item>
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -100,18 +100,20 @@
     <dimen name="searchpreferences_icon_size">32dp</dimen>
     <dimen name="tab_thumbnail_height">90dp</dimen>
     <dimen name="tab_thumbnail_width">160dp</dimen>
     <dimen name="tabs_counter_size">22sp</dimen>
     <dimen name="tabs_panel_indicator_width">60dp</dimen>
     <dimen name="tabs_panel_list_padding">16dip</dimen>
     <dimen name="tabs_list_divider_height">2dp</dimen>
     <dimen name="tabs_sidebar_width">200dp</dimen>
+    <dimen name="tabs_strip_height">40dp</dimen>
     <dimen name="tabs_strip_button_width">100dp</dimen>
     <dimen name="tabs_strip_button_padding">18dp</dimen>
+    <dimen name="tabs_strip_shadow_size">1dp</dimen>
     <dimen name="tabs_tray_horizontal_height">156dp</dimen>
     <dimen name="text_selection_handle_width">47dp</dimen>
     <dimen name="text_selection_handle_height">58dp</dimen>
     <dimen name="text_selection_handle_shadow">11dp</dimen>
     <dimen name="validation_message_height">50dp</dimen>
     <dimen name="validation_message_margin_top">6dp</dimen>
     <dimen name="url_bar_offset_left">32dp</dimen>
     <dimen name="history_tab_indicator_height">50dp</dimen>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -58,20 +58,16 @@
     <style name="Widget.GridView" parent="Widget.BaseGridView">
         <item name="android:verticalSpacing">0dip</item>
         <item name="android:horizontalSpacing">0dip</item>
         <item name="android:cacheColorHint">@android:color/transparent</item>
         <item name="android:listSelector">@drawable/action_bar_button</item>
     </style>
 
     <style name="Widget.Home.HomeList">
-        <item name="android:paddingTop">0dip</item>
-        <item name="android:paddingRight">0dip</item>
-        <item name="android:paddingLeft">0dip</item>
-        <item name="topDivider">true</item>
         <item name="android:scrollbarStyle">outsideOverlay</item>
     </style>
 
     <style name="Widget.ListItem">
         <item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
         <item name="android:textAppearance">?android:attr/textAppearanceLargeInverse</item>
         <item name="android:gravity">center_vertical</item>
         <item name="android:paddingLeft">12dip</item>
@@ -126,16 +122,35 @@
 
     <style name="Widget.TwoLinePageRow.Url">
         <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
         <item name="android:includeFontPadding">false</item>
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">middle</item>
     </style>
 
+    <style name="Widget.ReadingListRow" />
+
+    <style name="Widget.ReadingListRow.Title">
+        <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemTitle</item>
+        <item name="android:maxLines">2</item>
+        <item name="android:ellipsize">end</item>
+    </style>
+
+    <style name="Widget.ReadingListRow.Description">
+        <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
+        <item name="android:maxLines">4</item>
+        <item name="android:ellipsize">end</item>
+    </style>
+
+    <style name="Widget.ReadingListRow.ReadTime">
+        <item name="android:textStyle">italic</item>
+        <item name="android:textColor">@color/text_color_highlight</item>
+    </style>
+
     <style name="Widget.BookmarkFolderView" parent="Widget.TwoLinePageRow.Title">
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">none</item>
         <item name="android:paddingLeft">10dip</item>
         <item name="android:drawablePadding">10dip</item>
         <item name="android:drawableLeft">@drawable/bookmark_folder</item>
     </style>
 
@@ -224,17 +239,17 @@
     <style name="Widget.HomeBanner"/>
 
     <style name="Widget.Home" />
 
     <style name="Widget.Home.HeaderItem">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">32dp</item>
         <item name="android:textAppearance">@style/TextAppearance.Widget.Home.Header</item>
-        <item name="android:background">#fff5f7f9</item>
+        <item name="android:background">@color/background_light</item>
         <item name="android:focusable">false</item>
         <item name="android:gravity">center|left</item>
         <item name="android:paddingLeft">10dip</item>
         <item name="android:paddingRight">10dip</item>
     </style>
 
     <style name="Widget.Home.PageButton">
         <item name="android:layout_width">match_parent</item>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -293,16 +293,18 @@
   <string name="site_settings_title">&site_settings_title3;</string>
   <string name="site_settings_cancel">&site_settings_cancel;</string>
   <string name="site_settings_clear">&site_settings_clear;</string>
   <string name="site_settings_no_settings">&site_settings_no_settings;</string>
 
   <string name="reading_list_added">&reading_list_added;</string>
   <string name="reading_list_failed">&reading_list_failed;</string>
   <string name="reading_list_duplicate">&reading_list_duplicate;</string>
+  <string name="reading_list_time_minutes">&reading_list_time_minutes;</string>
+  <string name="reading_list_time_over_an_hour">&reading_list_time_over_an_hour;</string>
 
   <string name="page_action_dropmarker_description">&page_action_dropmarker_description;</string>
 
   <string name="contextmenu_open_new_tab">&contextmenu_open_new_tab;</string>
   <string name="contextmenu_open_private_tab">&contextmenu_open_private_tab;</string>
   <string name="contextmenu_remove">&contextmenu_remove;</string>
   <string name="contextmenu_add_to_launcher">&contextmenu_add_to_launcher;</string>
   <string name="contextmenu_share">&contextmenu_share;</string>
--- a/mobile/android/chrome/content/aboutAddons.js
+++ b/mobile/android/chrome/content/aboutAddons.js
@@ -532,17 +532,17 @@ var Addons = {
 
   onUninstalled: function(aAddon) {
     let list = document.getElementById("addons-list");
     let element = this._getElementForAddon(aAddon.id);
     list.removeChild(element);
 
     // Go back if we're in the detail view of the add-on that was uninstalled.
     let detailItem = document.querySelector("#addons-details > .addon-item");
-    if (detailItem.addon == aAddon) {
+    if (detailItem.addon.id == aAddon.id) {
       history.back();
     }
   },
 
   onInstallFailed: function(aInstall) {
   },
 
   onDownloadProgress: function xpidm_onDownloadProgress(aInstall) {
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -460,17 +460,17 @@ var BrowserApp = {
     // Broadcast a UIReady message so add-ons know we are finished with startup
     let event = document.createEvent("Events");
     event.initEvent("UIReady", true, false);
     window.dispatchEvent(event);
 
     if (this._startupStatus)
       this.onAppUpdated();
 
-    if (!ParentalControls.isAllowed(ParentalControls.INSTALL_EXTENSIONS)) {
+    if (!ParentalControls.isAllowed(ParentalControls.INSTALL_EXTENSION)) {
       // Disable extension installs
       Services.prefs.setIntPref("extensions.enabledScopes", 1);
       Services.prefs.setIntPref("extensions.autoDisableScopes", 1);
       Services.prefs.setBoolPref("xpinstall.enabled", false);
     }
 
     // notify java that gecko has loaded
     Messaging.sendRequest({ type: "Gecko:Ready" });
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -1,16 +1,16 @@
 # 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/.
 
 MOZ_APP_BASENAME=Fennec
 MOZ_APP_VENDOR=Mozilla
 
-MOZ_APP_VERSION=35.0a1
+MOZ_APP_VERSION=36.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/android/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 # We support Android SDK version 9 and up by default.
 # See the --enable-android-min-sdk and --enable-android-max-sdk arguments in configure.in.
--- a/mobile/android/search/java/org/mozilla/search/SearchWidget.java
+++ b/mobile/android/search/java/org/mozilla/search/SearchWidget.java
@@ -97,18 +97,23 @@ public class SearchWidget extends AppWid
             context.startActivity(redirect);
         }
 
         super.onReceive(context, intent);
     }
 
     // Utility to create the view for this widget and attach any event listeners to it
     private void addView(final AppWidgetManager manager, final Context context, final int id, final Bundle options) {
-        final int category = options.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
-        final boolean isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+        final boolean isKeyguard;
+        if (options != null) {
+            final int category = options.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
+            isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+        } else {
+            isKeyguard = false;
+        }
 
         final RemoteViews views;
         if (isKeyguard) {
             views = new RemoteViews(context.getPackageName(), R.layout.keyguard_widget);
         } else {
             views = new RemoteViews(context.getPackageName(), R.layout.search_widget);
             addClickIntent(context, views, R.id.search_button, ACTION_LAUNCH_SEARCH);
         }
--- a/netwerk/protocol/rtsp/controller/RtspController.cpp
+++ b/netwerk/protocol/rtsp/controller/RtspController.cpp
@@ -42,32 +42,27 @@
 #include "zlib.h"
 #include <algorithm>
 #include "nsDebug.h"
 
 extern PRLogModuleInfo* gRtspLog;
 #undef LOG
 #define LOG(args) PR_LOG(gRtspLog, PR_LOG_DEBUG, args)
 
-const unsigned long kCommandDelayMs = 200;
-
 namespace mozilla {
 namespace net {
 
 //-----------------------------------------------------------------------------
 // RtspController
 //-----------------------------------------------------------------------------
 NS_IMPL_ISUPPORTS(RtspController,
                   nsIStreamingProtocolController)
 
 RtspController::RtspController(nsIChannel *channel)
-  : mState(INIT),
-    mTimerLock("RtspController.mTimerLock"),
-    mPlayTimer(nullptr),
-    mPauseTimer(nullptr)
+  : mState(INIT)
 {
   LOG(("RtspController::RtspController()"));
 }
 
 RtspController::~RtspController()
 {
   LOG(("RtspController::~RtspController()"));
   if (mRtspSource.get()) {
@@ -94,72 +89,34 @@ RtspController::Play(void)
     MOZ_ASSERT(mRtspSource.get(), "mRtspSource should not be null!");
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   if (mState != CONNECTED) {
     return NS_ERROR_NOT_CONNECTED;
   }
 
-  MutexAutoLock lock(mTimerLock);
-  // Cancel the pause timer if it is active because successive pause-play in a
-  // short duration is unnecessary but could impair playback smoothing.
-  if (mPauseTimer) {
-    mPauseTimer->Cancel();
-    mPauseTimer = nullptr;
-  }
-
-  // Start a timer to delay the play operation for a short duration.
-  if (!mPlayTimer) {
-    mPlayTimer = do_CreateInstance("@mozilla.org/timer;1");
-    if (!mPlayTimer) {
-      return NS_ERROR_NOT_INITIALIZED;
-    }
-    mPlayTimer->InitWithFuncCallback(
-                  RtspController::PlayTimerCallback,
-                  this, kCommandDelayMs,
-                  nsITimer::TYPE_ONE_SHOT);
-  }
-
+  mRtspSource->play();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspController::Pause(void)
 {
   LOG(("RtspController::Pause()"));
   if (!mRtspSource.get()) {
     MOZ_ASSERT(mRtspSource.get(), "mRtspSource should not be null!");
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   if (mState != CONNECTED) {
     return NS_ERROR_NOT_CONNECTED;
   }
 
-  MutexAutoLock lock(mTimerLock);
-  // Cancel the play timer if it is active because successive play-pause in a
-  // short duration is unnecessary but could impair playback smoothing.
-  if (mPlayTimer) {
-    mPlayTimer->Cancel();
-    mPlayTimer = nullptr;
-  }
-
-  // Start a timer to delay the pause operation for a short duration.
-  if (!mPauseTimer) {
-    mPauseTimer = do_CreateInstance("@mozilla.org/timer;1");
-    if (!mPauseTimer) {
-      return NS_ERROR_NOT_INITIALIZED;
-    }
-    mPauseTimer->InitWithFuncCallback(
-                   RtspController::PauseTimerCallback,
-                   this, kCommandDelayMs,
-                   nsITimer::TYPE_ONE_SHOT);
-  }
-
+  mRtspSource->pause();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspController::Resume(void)
 {
   return Play();
 }
@@ -355,29 +312,16 @@ private:
 
 NS_IMETHODIMP
 RtspController::OnDisconnected(uint8_t index,
                                nsresult reason)
 {
   LOG(("RtspController::OnDisconnected() for track %d reason = 0x%x", index, reason));
   mState = DISCONNECTED;
 
-  // Ensure play and pause timer are stopped.
-  {
-    MutexAutoLock lock(mTimerLock);
-    if (mPlayTimer) {
-      mPlayTimer->Cancel();
-      mPlayTimer = nullptr;
-    }
-    if (mPauseTimer) {
-      mPauseTimer->Cancel();
-      mPauseTimer = nullptr;
-    }
-  }
-
   if (mListener) {
     nsRefPtr<SendOnDisconnectedTask> task =
       new SendOnDisconnectedTask(mListener, index, reason);
     // Break the cycle reference between the Listener (RtspControllerParent) and
     // us.
     mListener = nullptr;
     return NS_DispatchToMainThread(task);
   }
@@ -431,45 +375,10 @@ RtspController::PlaybackEnded()
     MOZ_ASSERT(mRtspSource.get(), "mRtspSource should not be null!");
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   mRtspSource->playbackEnded();
   return NS_OK;
 }
 
-//-----------------------------------------------------------------------------
-// RtspController static member methods
-//-----------------------------------------------------------------------------
-//static
-void RtspController::PlayTimerCallback(nsITimer *aTimer, void *aClosure)
-{
-  MOZ_ASSERT(aTimer);
-  MOZ_ASSERT(aClosure);
-
-  RtspController *self = static_cast<RtspController*>(aClosure);
-  MOZ_ASSERT(self->mRtspSource.get());
-
-  MutexAutoLock lock(self->mTimerLock);
-  if (self->mPlayTimer) {
-    self->mRtspSource->play();
-    self->mPlayTimer = nullptr;
-  }
-}
-
-//static
-void RtspController::PauseTimerCallback(nsITimer *aTimer, void *aClosure)
-{
-  MOZ_ASSERT(aTimer);
-  MOZ_ASSERT(aClosure);
-
-  RtspController *self = static_cast<RtspController*>(aClosure);
-  MOZ_ASSERT(self->mRtspSource.get());
-
-  MutexAutoLock lock(self->mTimerLock);
-  if (self->mPauseTimer) {
-    self->mRtspSource->pause();
-    self->mPauseTimer = nullptr;
-  }
-}
-
 } // namespace mozilla::net
 } // namespace mozilla
--- a/netwerk/protocol/rtsp/controller/RtspController.h
+++ b/netwerk/protocol/rtsp/controller/RtspController.h
@@ -2,42 +2,36 @@
 /* vim: set sw=2 ts=8 et 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 RtspController_h
 #define RtspController_h
 
-#include "mozilla/Mutex.h"
 #include "nsIStreamingProtocolController.h"
 #include "nsIChannel.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
-#include "nsITimer.h"
 #include "RTSPSource.h"
 
 namespace mozilla {
 namespace net {
 
 class RtspController : public nsIStreamingProtocolController
                      , public nsIStreamingProtocolListener
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSISTREAMINGPROTOCOLCONTROLLER
   NS_DECL_NSISTREAMINGPROTOCOLLISTENER
 
   RtspController(nsIChannel *channel);
   ~RtspController();
 
-  // These callbacks will be called when mPlayTimer/mPauseTimer fires.
-  static void PlayTimerCallback(nsITimer *aTimer, void *aClosure);
-  static void PauseTimerCallback(nsITimer *aTimer, void *aClosure);
-
 private:
   enum State {
     INIT,
     CONNECTED,
     DISCONNECTED
   };
 
   // RTSP URL refer to a stream or an aggregate of streams.
@@ -48,20 +42,13 @@ private:
   nsCString mSpec;
   // UserAgent string.
   nsCString mUserAgent;
   // Indicate the connection state between the
   // media streaming server and the Rtsp client.
   State mState;
   // Rtsp Streaming source.
   android::sp<android::RTSPSource> mRtspSource;
-  // This lock protects mPlayTimer and mPauseTimer.
-  Mutex mTimerLock;
-  // Timers to delay the play and pause operations.
-  // They are used for optimization and avoid sending unnecessary requests to
-  // the server.
-  nsCOMPtr<nsITimer> mPlayTimer;
-  nsCOMPtr<nsITimer> mPauseTimer;
 };
 
 }
 } // namespace mozilla::net
 #endif
--- a/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
+++ b/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
@@ -16,16 +16,18 @@
 #include "nsStringStream.h"
 #include "prlog.h"
 
 PRLogModuleInfo* gRtspChildLog = nullptr;
 #undef LOG
 #define LOG(args) PR_LOG(gRtspChildLog, PR_LOG_DEBUG, args)
 
 const uint32_t kRtspTotalTracks = 2;
+const unsigned long kRtspCommandDelayMs = 200;
+
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ADDREF(RtspControllerChild)
 
 NS_IMETHODIMP_(nsrefcnt) RtspControllerChild::Release()
@@ -59,16 +61,19 @@ NS_INTERFACE_MAP_END
 // RtspControllerChild methods
 //-----------------------------------------------------------------------------
 RtspControllerChild::RtspControllerChild(nsIChannel *channel)
   : mIPCOpen(false)
   , mIPCAllowed(false)
   , mChannel(channel)
   , mTotalTracks(0)
   , mSuspendCount(0)
+  , mTimerLock("RtspControllerChild.mTimerLock")
+  , mPlayTimer(nullptr)
+  , mPauseTimer(nullptr)
 {
 #if defined(PR_LOGGING)
   if (!gRtspChildLog)
     gRtspChildLog = PR_NewLogModule("nsRtspChild");
 #endif
   AddIPDLReference();
   gNeckoChild->SendPRtspControllerConstructor(this);
 }
@@ -103,16 +108,30 @@ RtspControllerChild::AllowIPC()
 
 void
 RtspControllerChild::DisallowIPC()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mIPCAllowed = false;
 }
 
+void
+RtspControllerChild::StopPlayAndPauseTimer()
+{
+  MutexAutoLock lock(mTimerLock);
+  if (mPlayTimer) {
+    mPlayTimer->Cancel();
+    mPlayTimer = nullptr;
+  }
+  if (mPauseTimer) {
+    mPauseTimer->Cancel();
+    mPauseTimer = nullptr;
+  }
+}
+
 //-----------------------------------------------------------------------------
 // RtspControllerChild::PRtspControllerChild
 //-----------------------------------------------------------------------------
 bool
 RtspControllerChild::RecvOnMediaDataAvailable(
                        const uint8_t& index,
                        const nsCString& data,
                        const uint32_t& length,
@@ -169,28 +188,30 @@ RtspControllerChild::RecvOnConnected(
   return true;
 }
 
 bool
 RtspControllerChild::RecvOnDisconnected(
                        const uint8_t& index,
                        const nsresult& reason)
 {
+  StopPlayAndPauseTimer();
   DisallowIPC();
   LOG(("RtspControllerChild::RecvOnDisconnected for track %d reason = 0x%x", index, reason));
   if (mListener) {
     mListener->OnDisconnected(index, reason);
   }
   ReleaseChannel();
   return true;
 }
 
 bool
 RtspControllerChild::RecvAsyncOpenFailed(const nsresult& reason)
 {
+  StopPlayAndPauseTimer();
   DisallowIPC();
   LOG(("RtspControllerChild::RecvAsyncOpenFailed reason = 0x%x", reason));
   if (mListener) {
     mListener->OnDisconnected(0, NS_ERROR_CONNECTION_REFUSED);
   }
   ReleaseChannel();
   return true;
 }
@@ -229,18 +250,16 @@ RtspControllerChild::GetTrackMetaData(
 }
 
 enum IPCEvent
 {
   SendNoneEvent = 0,
   SendPlayEvent,
   SendPauseEvent,
   SendSeekEvent,
-  SendResumeEvent,
-  SendSuspendEvent,
   SendStopEvent,
   SendPlaybackEndedEvent
 };
 
 class SendIPCEvent : public nsRunnable
 {
 public:
   SendIPCEvent(RtspControllerChild *aController, IPCEvent aEvent)
@@ -270,20 +289,16 @@ public:
     bool rv = true;
 
     if (mEvent == SendPlayEvent) {
       rv = mController->SendPlay();
     } else if (mEvent == SendPauseEvent) {
       rv = mController->SendPause();
     } else if (mEvent == SendSeekEvent) {
       rv = mController->SendSeek(mSeekTime);
-    } else if (mEvent == SendResumeEvent) {
-      rv = mController->SendResume();
-    } else if (mEvent == SendSuspendEvent) {
-      rv = mController->SendSuspend();
     } else if (mEvent == SendStopEvent) {
       rv = mController->SendStop();
     } else if (mEvent == SendPlaybackEndedEvent) {
       rv = mController->SendPlaybackEnded();
     } else {
       LOG(("RtspControllerChild::SendIPCEvent"));
     }
     if (!rv) {
@@ -300,83 +315,98 @@ private:
 //-----------------------------------------------------------------------------
 // RtspControllerChild::nsIStreamingProtocolController
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 RtspControllerChild::Play(void)
 {
   LOG(("RtspControllerChild::Play()"));
 
-  if (NS_IsMainThread()) {
-    if (!OKToSendIPC() || !SendPlay()) {
-      return NS_ERROR_FAILURE;
+  MutexAutoLock lock(mTimerLock);
+  // Cancel the pause timer if it is active because successive pause-play in a
+  // short duration is unncessary but could impair playback smoothing.
+  if (mPauseTimer) {
+    mPauseTimer->Cancel();
+    mPauseTimer = nullptr;
+  }
+
+  // Start a timer to delay the play operation for a short duration.
+  if (!mPlayTimer) {
+    mPlayTimer = do_CreateInstance("@mozilla.org/timer;1");
+    if (!mPlayTimer) {
+      return NS_ERROR_NOT_INITIALIZED;
     }
-  } else {
-    nsresult rv = NS_DispatchToMainThread(
-                    new SendIPCEvent(this, SendPlayEvent));
-    NS_ENSURE_SUCCESS(rv, rv);
+    // We have to dispatch the timer callback to the main thread because the
+    // decoder thread is a thread from nsIThreadPool and cannot be the timer
+    // target. Furthermore, IPC send functions should only be called from the
+    // main thread.
+    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+    mPlayTimer->SetTarget(mainThread);
+    mPlayTimer->InitWithFuncCallback(
+                  RtspControllerChild::PlayTimerCallback,
+                  this, kRtspCommandDelayMs,
+                  nsITimer::TYPE_ONE_SHOT);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspControllerChild::Pause(void)
 {
   LOG(("RtspControllerChild::Pause()"));
 
-  if (NS_IsMainThread()) {
-    if (!OKToSendIPC() || !SendPause()) {
-      return NS_ERROR_FAILURE;
+  MutexAutoLock lock(mTimerLock);
+  // Cancel the play timer if it is active because successive play-pause in a
+  // shrot duration is unnecessary but could impair playback smoothing.
+  if (mPlayTimer) {
+    mPlayTimer->Cancel();
+    mPlayTimer = nullptr;
+  }
+
+  // Start a timer to delay the pause operation for a short duration.
+  if (!mPauseTimer) {
+    mPauseTimer = do_CreateInstance("@mozilla.org/timer;1");
+    if (!mPauseTimer) {
+      return NS_ERROR_NOT_INITIALIZED;
     }
-  } else {
-    nsresult rv = NS_DispatchToMainThread(
-                    new SendIPCEvent(this, SendPauseEvent));
-    NS_ENSURE_SUCCESS(rv, rv);
+    // We have to dispatch the timer callback to the main thread because the
+    // decoder thread is a thread from nsIThreadPool and cannot be the timer
+    // target.
+    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+    mPauseTimer->SetTarget(mainThread);
+    mPauseTimer->InitWithFuncCallback(
+                  RtspControllerChild::PauseTimerCallback,
+                  this, kRtspCommandDelayMs,
+                  nsITimer::TYPE_ONE_SHOT);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspControllerChild::Resume(void)
 {
   LOG(("RtspControllerChild::Resume()"));
   NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
 
   if (!--mSuspendCount) {
-    if (NS_IsMainThread()) {
-      if (!OKToSendIPC() || !SendResume()) {
-        return NS_ERROR_FAILURE;
-      }
-    } else {
-      nsresult rv = NS_DispatchToMainThread(
-                      new SendIPCEvent(this, SendResumeEvent));
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
+    return Play();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspControllerChild::Suspend(void)
 {
   LOG(("RtspControllerChild::Suspend()"));
 
   if (!mSuspendCount++) {
-    if (NS_IsMainThread()) {
-      if (!OKToSendIPC() || !SendSuspend()) {
-        return NS_ERROR_FAILURE;
-      }
-    } else {
-      nsresult rv = NS_DispatchToMainThread(
-                      new SendIPCEvent(this, SendSuspendEvent));
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
+    return Pause();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspControllerChild::Seek(uint64_t seekTimeUs)
 {
@@ -394,16 +424,17 @@ RtspControllerChild::Seek(uint64_t seekT
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspControllerChild::Stop()
 {
   LOG(("RtspControllerChild::Stop()"));
+  StopPlayAndPauseTimer();
 
   if (NS_IsMainThread()) {
     if (!OKToSendIPC() || !SendStop()) {
       return NS_ERROR_FAILURE;
     }
     DisallowIPC();
   } else {
     nsresult rv = NS_DispatchToMainThread(
@@ -537,10 +568,49 @@ RtspControllerChild::AsyncOpen(nsIStream
   SerializeURI(uri, uriParams);
 
   if (!OKToSendIPC() || !SendAsyncOpen(uriParams)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// RtspControllerChild static member methods
+//-----------------------------------------------------------------------------
+//static
+void
+RtspControllerChild::PlayTimerCallback(nsITimer *aTimer, void *aClosure)
+{
+  MOZ_ASSERT(aTimer);
+  MOZ_ASSERT(aClosure);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RtspControllerChild *self = static_cast<RtspControllerChild*>(aClosure);
+
+  MutexAutoLock lock(self->mTimerLock);
+  if (!self->mPlayTimer || !self->OKToSendIPC()) {
+    return;
+  }
+  self->SendPlay();
+  self->mPlayTimer = nullptr;
+}
+
+//static
+void
+RtspControllerChild::PauseTimerCallback(nsITimer *aTimer, void *aClosure)
+{
+  MOZ_ASSERT(aTimer);
+  MOZ_ASSERT(aClosure);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RtspControllerChild *self = static_cast<RtspControllerChild*>(aClosure);
+
+  MutexAutoLock lock(self->mTimerLock);
+  if (!self->mPauseTimer || !self->OKToSendIPC()) {
+    return;
+  }
+  self->SendPause();
+  self->mPauseTimer = nullptr;
+}
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/rtsp/controller/RtspControllerChild.h
+++ b/netwerk/protocol/rtsp/controller/RtspControllerChild.h
@@ -9,16 +9,18 @@
 
 #include "mozilla/net/PRtspControllerChild.h"
 #include "nsIStreamingProtocolController.h"
 #include "nsIChannel.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "mozilla/net/RtspChannelChild.h"
+#include "mozilla/Mutex.h"
+#include "nsITimer.h"
 
 namespace mozilla {
 namespace net {
 
 class RtspControllerChild : public nsIStreamingProtocolController
                           , public nsIStreamingProtocolListener
                           , public PRtspControllerChild
 {
@@ -47,16 +49,20 @@ class RtspControllerChild : public nsISt
   void AddIPDLReference();
   void ReleaseIPDLReference();
   void AddMetaData(already_AddRefed<nsIStreamingProtocolMetaData>&& meta);
   int  GetMetaDataLength();
   bool OKToSendIPC();
   void AllowIPC();
   void DisallowIPC();
 
+  // These callbacks will be called when mPlayTimer/mPauseTimer fires.
+  static void PlayTimerCallback(nsITimer *aTimer, void *aClosure);
+  static void PauseTimerCallback(nsITimer *aTimer, void *aClosure);
+
  private:
   bool mIPCOpen;
   // The intention of this variable is just to avoid any IPC message to be sent
   // when this flag is set as false. Nothing more.
   bool mIPCAllowed;
   // Dummy channel used to aid MediaResource creation in HTMLMediaElement.
   nsCOMPtr<nsIChannel> mChannel;
   // The nsIStreamingProtocolListener implementation.
@@ -68,13 +74,23 @@ class RtspControllerChild : public nsISt
   // ASCII encoded URL spec
   nsCString mSpec;
   // The total tracks for the given media stream session.
   uint32_t mTotalTracks;
   // Current suspension depth for this channel object
   uint32_t mSuspendCount;
   // Detach channel-controller relationship.
   void ReleaseChannel();
+  // This lock protects mPlayTimer and mPauseTimer.
+  Mutex mTimerLock;
+  // Timers to delay the play and pause operations.
+  // They are used for optimization and to avoid sending unnecessary requests to
+  // the server.
+  nsCOMPtr<nsITimer> mPlayTimer;
+  nsCOMPtr<nsITimer> mPauseTimer;
+  // Timers should be stopped if we are going to terminate, such as when
+  // receiving Stop command or OnDisconnected event.
+  void StopPlayAndPauseTimer();
 };
 } // namespace net
 } // namespace mozilla
 
 #endif // RtspControllerChild_h
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -1,14 +1,14 @@
 # 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/.
 
 # Definitions used by constants.js.
-weave_version := 1.37.0
+weave_version := 1.38.0
 weave_id      := {340c2bbc-ce74-4362-90b5-7c26312808ef}
 
 # Preprocess files.
 SYNC_PP := modules/constants.js
 SYNC_PP_FLAGS := \
  -Dweave_version=$(weave_version) \
  -Dweave_id='$(weave_id)'
 SYNC_PP_PATH = $(FINAL_TARGET)/modules/services-sync
--- a/toolkit/components/parentalcontrols/nsIParentalControlsService.idl
+++ b/toolkit/components/parentalcontrols/nsIParentalControlsService.idl
@@ -6,31 +6,33 @@
 
 #include "nsISupports.idl"
 
 interface nsIURI;
 interface nsIFile;
 interface nsIInterfaceRequestor;
 interface nsIArray;
 
-[scriptable, uuid(4bde6754-406a-45d1-b18e-dc685adc1db4)]
+[scriptable, uuid(e7bcc22c-e9fc-4e7d-88b9-7482399b322d)]
 interface nsIParentalControlsService : nsISupports
 {
   /**
    * Action types that can be blocked for users.
    */
   const short DOWNLOAD = 1; // Downloading files
   const short INSTALL_EXTENSION = 2; // Installing extensions
   const short INSTALL_APP = 3; // Installing webapps
   const short VISIT_FILE_URLS = 4; // Opening file:/// urls
   const short SHARE = 5; // Sharing
   const short BOOKMARK = 6; // Creating bookmarks
   const short ADD_CONTACT = 7; // Add contacts to the system database
   const short SET_IMAGE = 8; // Setting images as wall paper
   const short MODIFY_ACCOUNTS = 9; // Modifying system accounts
+  const short REMOTE_DEBUGGING = 10; // Remote debugging
+  const short IMPORT_SETTINGS = 11; // Importing settings from other apps
 
   /**
    * @returns true if the current user account has parental controls
    * restrictions enabled.
    */ 
   readonly attribute boolean parentalControlsEnabled;
 
   /**
--- a/xpcom/components/Module.h
+++ b/xpcom/components/Module.h
@@ -16,17 +16,17 @@ namespace mozilla {
 /**
  * A module implements one or more XPCOM components. This structure is used
  * for both binary and script modules, but the registration members
  * (cids/contractids/categoryentries) are unused for modules which are loaded
  * via a module loader.
  */
 struct Module
 {
-  static const unsigned int kVersion = 35;
+  static const unsigned int kVersion = 36;
 
   struct CIDEntry;
 
   typedef already_AddRefed<nsIFactory> (*GetFactoryProcPtr)(
     const Module& module, const CIDEntry& entry);
 
   typedef nsresult (*ConstructorProcPtr)(nsISupports* aOuter,
                                          const nsIID& aIID,