Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Thu, 08 Oct 2015 14:35:43 -0700
changeset 266995 1a5167cd76888a6cfe7d94ab333fe444c7b0681b
parent 266994 fd660e3112d6f2f1d9d121450eaff6ed1ac31a76 (current diff)
parent 266894 e5f1bc63ad52d0eb86f7fb838226ca6036774660 (diff)
child 266996 bf388a8e620ba36cbb15fd3393d2c67838096531
push id29504
push usercbook@mozilla.com
push dateFri, 09 Oct 2015 09:43:23 +0000
treeherdermozilla-central@d01dd42e654b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound, a=merge
b2g/simulator/lib/main.js
b2g/simulator/lib/simulator-process.js
b2g/simulator/options.xul.in
mobile/android/base/GeckoEvent.java
testing/taskcluster/tasks/branches/base_job_flags.yml
widget/android/AndroidJavaWrappers.cpp
widget/android/nsAppShell.cpp
--- a/b2g/components/LogShake.jsm
+++ b/b2g/components/LogShake.jsm
@@ -123,17 +123,20 @@ var LogShake = {
     "/proc/cmdline": LogParser.prettyPrintArray,
     "/proc/kmsg": LogParser.prettyPrintArray,
     "/proc/last_kmsg": LogParser.prettyPrintArray,
     "/proc/meminfo": LogParser.prettyPrintArray,
     "/proc/uptime": LogParser.prettyPrintArray,
     "/proc/version": LogParser.prettyPrintArray,
     "/proc/vmallocinfo": LogParser.prettyPrintArray,
     "/proc/vmstat": LogParser.prettyPrintArray,
-    "/system/b2g/application.ini": LogParser.prettyPrintArray
+    "/system/b2g/application.ini": LogParser.prettyPrintArray,
+    "/cache/recovery/last_install": LogParser.prettyPrintArray,
+    "/cache/recovery/last_kmsg": LogParser.prettyPrintArray,
+    "/cache/recovery/last_log": LogParser.prettyPrintArray
   },
 
   /**
    * Start existing, observing motion events if the screen is turned on.
    */
   init: function() {
     // TODO: no way of querying screen state from power manager
     // this.handleScreenChangeEvent({ detail: {
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,20 +10,20 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,20 +10,20 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,18 +14,18 @@
   <!--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="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <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="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="065f6361461030d32c6dc08d716b013bfadab1d9"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,18 +12,18 @@
   <!--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="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <!-- 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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,19 +10,19 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,19 +10,19 @@
   <!--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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,18 +14,18 @@
   <!--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="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <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="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="065f6361461030d32c6dc08d716b013bfadab1d9"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,20 +10,20 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "4973f57cd8f9a62a95f783a24eac32da2bde99fc", 
+        "git_revision": "e698df503ff700eb5782e3d50c6eb753567d3451", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "c728de03bc96ef160fd5a662b3efcd5cf2c2b844", 
+    "revision": "bd073200a776c714b8160a38c77f980b19fd97c2", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -10,20 +10,20 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -13,18 +13,18 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <!-- 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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,20 +10,20 @@
   <!--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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
--- a/b2g/simulator/build_xpi.py
+++ b/b2g/simulator/build_xpi.py
@@ -5,17 +5,16 @@
 # Generate xpi for the simulator addon by:
 # - building a special gaia profile for it, as we need:
 #     * more languages, and,
 #     * less apps
 #   than b2g desktop's one
 # - retrieve usefull app version metadata from the build system
 # - finally, use addon sdk's cfx tool to build the addon xpi
 #   that ships:
-#     * a small firefox addon registering to the app manager
 #     * b2g desktop runtime
 #     * gaia profile
 
 import sys, os, re, subprocess
 from mozbuild.preprocessor import Preprocessor
 from mozbuild.base import MozbuildObject
 from mozbuild.util import ensureParentDir
 from mozpack.mozjar import JarWriter
@@ -121,29 +120,20 @@ def main(platform):
     # Preprocess some files...
     manifest = os.path.join(build.topobjdir, "b2g", "simulator", "install.rdf")
     preprocess_file(os.path.join(srcdir, "install.rdf.in"),
                     manifest,
                     version,
                     app_buildid,
                     update_url)
 
-    options_file = os.path.join(build.topobjdir, "b2g", "simulator", "options.xul")
-    preprocess_file(os.path.join(srcdir, "options.xul.in"),
-                    options_file,
-                    version,
-                    app_buildid,
-                    update_url)
-
     with JarWriter(xpi_path, optimize=False) as zip:
         # Ship addon files into the .xpi
-        add_dir_to_zip(zip, os.path.join(srcdir, "lib"), "lib")
         add_file_to_zip(zip, manifest, "install.rdf")
         add_file_to_zip(zip, os.path.join(srcdir, "bootstrap.js"), "bootstrap.js")
-        add_file_to_zip(zip, options_file, "options.xul")
         add_file_to_zip(zip, os.path.join(srcdir, "icon.png"), "icon.png")
         add_file_to_zip(zip, os.path.join(srcdir, "icon64.png"), "icon64.png")
 
         # Ship b2g-desktop, but prevent its gaia profile to be shipped in the xpi
         add_dir_to_zip(zip, os.path.join(distdir, "b2g"), "b2g",
                        ("gaia", "B2G.app/Contents/MacOS/gaia",
                         "B2G.app/Contents/Resources/gaia"))
         # Then ship our own gaia profile
deleted file mode 100644
--- a/b2g/simulator/lib/main.js
+++ /dev/null
@@ -1,92 +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/.
- */
-
-const { Cc, Ci, Cu } = require("chrome");
-
-const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
-const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
-const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-const { Simulator } = Cu.import("resource://gre/modules/devtools/shared/apps/Simulator.jsm");
-const { SimulatorProcess } = require("./simulator-process");
-const Runtime = require("sdk/system/runtime");
-const URL = require("sdk/url");
-
-const ROOT_URI = require("addon").uri;
-const PROFILE_URL = ROOT_URI + "profile/";
-const BIN_URL = ROOT_URI + "b2g/";
-
-var process;
-
-function launch(options) {
-  // Close already opened simulation.
-  if (process) {
-    return close().then(launch.bind(null, options));
-  }
-
-  // Compute B2G runtime path.
-  let path;
-  try {
-    let pref = "extensions." + require("addon").id + ".customRuntime";
-    path = Services.prefs.getComplexValue(pref, Ci.nsIFile);
-  } catch(e) {}
-
-  if (!path) {
-    let executables = {
-      WINNT: "b2g-bin.exe",
-      Darwin: "B2G.app/Contents/MacOS/b2g-bin",
-      Linux: "b2g-bin",
-    };
-    path = URL.toFilename(BIN_URL);
-    path += Runtime.OS == "WINNT" ? "\\" : "/";
-    path += executables[Runtime.OS];
-  }
-  options.runtimePath = path;
-  console.log("simulator path:", options.runtimePath);
-
-  // Compute Gaia profile path.
-  if (!options.profilePath) {
-    let gaiaProfile;
-    try {
-      let pref = "extensions." + require("addon").id + ".gaiaProfile";
-      gaiaProfile = Services.prefs.getComplexValue(pref, Ci.nsIFile).path;
-    } catch(e) {}
-
-    options.profilePath = gaiaProfile || URL.toFilename(PROFILE_URL);
-  }
-
-  process = new SimulatorProcess(options);
-  process.run();
-
-  return promise.resolve();
-}
-
-function close() {
-  if (!process) {
-    return promise.resolve();
-  }
-  let p = process;
-  process = null;
-  return p.kill();
-}
-
-var name;
-
-AddonManager.getAddonByID(require("addon").id, function (addon) {
-  name = addon.name.replace(" Simulator", "");
-
-  Simulator.register(name, {
-    // We keep the deprecated `appinfo` object so that recent simulator addons
-    // remain forward-compatible with older Firefox.
-    appinfo: { label: name },
-    launch: launch,
-    close: close
-  });
-});
-
-exports.shutdown = function () {
-  Simulator.unregister(name);
-  close();
-}
-
deleted file mode 100644
--- a/b2g/simulator/lib/simulator-process.js
+++ /dev/null
@@ -1,165 +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';
-
-const { Cc, Ci, Cu, ChromeWorker } = require("chrome");
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-const Environment = require("sdk/system/environment").env;
-const Runtime = require("sdk/system/runtime");
-const Subprocess = require("sdk/system/child_process/subprocess");
-const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
-const { EventEmitter } = Cu.import("resource://gre/modules/devtools/shared/event-emitter.js", {});
-
-
-// Log subprocess error and debug messages to the console.  This logs messages
-// for all consumers of the API.  We trim the messages because they sometimes
-// have trailing newlines.  And note that registerLogHandler actually registers
-// an error handler, despite its name.
-Subprocess.registerLogHandler(
-  s => console.error("subprocess: " + s.trim())
-);
-Subprocess.registerDebugHandler(
-  s => console.debug("subprocess: " + s.trim())
-);
-
-function SimulatorProcess(options) {
-  this.options = options;
-
-  EventEmitter.decorate(this);
-  this.on("stdout", (e, data) => { console.log(data.trim()) });
-  this.on("stderr", (e, data) => { console.error(data.trim()) });
-}
-
-SimulatorProcess.prototype = {
-
-  // check if b2g is running
-  get isRunning() {
-    return !!this.process;
-  },
-
-  /**
-   * Start the process and connect the debugger client.
-   */
-  run: function() {
-    // kill before start if already running
-    if (this.process != null) {
-      this.process
-          .kill()
-          .then(this.run.bind(this));
-      return;
-    }
-
-    // resolve b2g binaries path (raise exception if not found)
-    let b2gExecutable = this.b2gExecutable;
-
-    this.once("stdout", function () {
-      if (Runtime.OS == "Darwin") {
-          console.debug("WORKAROUND run osascript to show b2g-desktop window"+
-                        " on Runtime.OS=='Darwin'");
-        // Escape double quotes and escape characters for use in AppleScript.
-        let path = b2gExecutable.path
-          .replace(/\\/g, "\\\\").replace(/\"/g, '\\"');
-
-        Subprocess.call({
-          command: "/usr/bin/osascript",
-          arguments: ["-e", 'tell application "' + path + '" to activate'],
-        });
-      }
-    });
-
-    let environment;
-    if (Runtime.OS == "Linux") {
-      environment = ["TMPDIR=" + Services.dirsvc.get("TmpD", Ci.nsIFile).path];
-      if ("DISPLAY" in Environment) {
-        environment.push("DISPLAY=" + Environment.DISPLAY);
-      }
-    }
-
-    // spawn a b2g instance
-    this.process = Subprocess.call({
-      command: b2gExecutable,
-      arguments: this.b2gArguments,
-      environment: environment,
-
-      // emit stdout event
-      stdout: data => {
-        this.emit("stdout", data);
-      },
-
-      // emit stderr event
-      stderr: data => {
-        this.emit("stderr", data);
-      },
-
-      // on b2g instance exit, reset tracked process, remote debugger port and
-      // shuttingDown flag, then finally emit an exit event
-      done: (function(result) {
-        console.log("B2G terminated with " + result.exitCode);
-        this.process = null;
-        this.emit("exit", result.exitCode);
-      }).bind(this)
-    });
-  },
-
-  // request a b2g instance kill
-  kill: function() {
-    let deferred = promise.defer();
-    if (this.process) {
-      this.once("exit", (e, exitCode) => {
-        this.shuttingDown = false;
-        deferred.resolve(exitCode);
-      });
-      if (!this.shuttingDown) {
-        this.shuttingDown = true;
-        this.emit("kill", null);
-        this.process.kill();
-      }
-      return deferred.promise;
-    } else {
-      return promise.resolve(undefined);
-    }
-  },
-
-  // compute current b2g file handle
-  get b2gExecutable() {
-    if (this._executable) {
-      return this._executable;
-    }
-
-    let executable = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
-    executable.initWithPath(this.options.runtimePath);
-
-    if (!executable.exists()) {
-      // B2G binaries not found
-      throw Error("b2g-desktop Executable not found.");
-    }
-
-    this._executable = executable;
-
-    return executable;
-  },
-
-  // compute b2g CLI arguments
-  get b2gArguments() {
-    let args = [];
-
-    let profile = this.options.profilePath;
-    args.push("-profile", profile);
-    console.log("profile", profile);
-
-    // NOTE: push dbgport option on the b2g-desktop commandline
-    args.push("-start-debugger-server", "" + this.options.port);
-
-    // Ignore eventual zombie instances of b2g that are left over
-    args.push("-no-remote");
-
-    return args;
-  },
-};
-
-exports.SimulatorProcess = SimulatorProcess;
deleted file mode 100644
--- a/b2g/simulator/options.xul.in
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" ?>
-<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <setting pref="extensions.@ADDON_ID@.gaiaProfile" type="directory" title="Select a custom Gaia profile directory"/>
-  <setting pref="extensions.@ADDON_ID@.customRuntime" type="file" title="Select a custom runtime executable"/>
-</vbox>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -914,46 +914,46 @@ notification[value="loop-sharing-notific
   display: none;
 }
 
 /* Social */
 /* Note the chatbox 'width' values are duplicated in socialchat.xml */
 chatbox {
   -moz-binding: url("chrome://browser/content/socialchat.xml#chatbox");
   transition: height 150ms ease-out, width 150ms ease-out;
-  height: 285px;
-  width: 260px; /* CHAT_WIDTH_OPEN in socialchat.xml */
+  height: 290px;
+  width: 300px; /* CHAT_WIDTH_OPEN in socialchat.xml */
 }
 
 chatbox[customSize] {
-  width: 300px; /* CHAT_WIDTH_OPEN_ALT in socialchat.xml */
+  width: 350px; /* CHAT_WIDTH_OPEN_ALT in socialchat.xml */
 }
 
 #chat-window[customSize] {
-  min-width: 300px;
+  min-width: 350px;
 }
 
 chatbox[customSize="loopChatEnabled"] {
   /* 325px as defined per UX */
   height: 325px;
 }
 
 #chat-window[customSize="loopChatEnabled"] {
   /* 325px + 30px top bar height. */
   min-height: calc(325px + 30px);
 }
 
 chatbox[customSize="loopChatMessageAppended"] {
-  /* 445px as defined per UX */
-  height: 445px;
+  /* 400px as defined per UX */
+  height: 400px;
 }
 
 #chat-window[customSize="loopChatMessageAppended"] {
   /* 445px + 30px top bar height. */
-  min-height: calc(445px + 30px);
+  min-height: calc(400px + 30px);
 }
 
 chatbox[minimized="true"] {
   width: 160px;
   height: 20px; /* CHAT_WIDTH_MINIMIZED in socialchat.xml */
 }
 
 chatbar {
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -1,15 +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/. */
 
-var Cu = Components.utils;
-Cu.import("resource://gre/modules/LoadContextInfo.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
 
 //******** define a js object to implement nsITreeView
 function pageInfoTreeView(treeid, copycol)
 {
   // copycol is the index number for the column that we want to add to
   // the copy-n-paste buffer when the user hits accel-c
   this.treeid = treeid;
   this.copycol = copycol;
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -468,18 +468,18 @@
         ]]></body>
       </method>
 
       <method name="getTotalChildWidth">
         <parameter name="aChatbox"/>
         <body><![CDATA[
           // These are from the CSS for the chatbox and must be kept in sync.
           // We can't use calcTotalWidthOf due to the transitions...
-          const CHAT_WIDTH_OPEN = 260;
-          const CHAT_WIDTH_OPEN_ALT = 300;
+          const CHAT_WIDTH_OPEN = 300;
+          const CHAT_WIDTH_OPEN_ALT = 350;
           const CHAT_WIDTH_MINIMIZED = 160;
           let openWidth = aChatbox.hasAttribute("customSize") ?
             CHAT_WIDTH_OPEN_ALT : CHAT_WIDTH_OPEN;
 
           return aChatbox.minimized ? CHAT_WIDTH_MINIMIZED : openWidth;
         ]]></body>
       </method>
 
--- a/browser/components/loop/content/css/panel.css
+++ b/browser/components/loop/content/css/panel.css
@@ -71,174 +71,32 @@ body {
 .sign-in-request-button {
   font-size: 1rem;
   margin: 1rem;
   width: 80%;
   padding: .5rem 1rem;
   border-radius: 3px;
 }
 
-/* Tabs and tab selection buttons */
-
-.tab-view-container {
-  width: 100%;
-  background-image: url("../shared/img/beta-ribbon.svg#beta-ribbon");
-  background-color: #fbfbfb;
-  background-size: 36px 36px;
-  background-repeat: no-repeat;
-  flex: 1;
-  display: flex;
-  flex-flow: column nowrap;
-  overflow: hidden;
-}
-
-.tab-view {
-  position: relative;
-  width: 100%;
-  height: 4rem;
-  line-height: 3.7rem;
-  color: #4A4A4A;
-  list-style: none;
-  border-bottom: 2px solid #ccc;
-}
-
-.tab-view > li {
-  display: inline-block;
-  text-align: center;
-  padding: 0;
-  cursor: pointer;
-}
-
-.tab-view > .slide-bar {
-  position: absolute;
-  bottom: -2px;
-  left: 0;
-  height: .2em;
-  width: 50%;
-  background: #00A9DC;
-  border: none;
-  transition: margin .3s ease-in-out;
-}
-
-.tab-view li:nth-child(1).selected ~ .slide-bar {
-  margin-left: 0;
-}
-
-.tab-view li:nth-child(2).selected ~ .slide-bar {
-  margin-left: 50%;
-}
-
-html[dir="rtl"] .tab-view li:nth-child(1).selected ~ .slide-bar {
-  margin-left: 50%;
-}
-
-html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar {
-  margin-left: 0;
-}
-
-.tab-view > li > div {
-  font-size: 1.2rem;
-  pointer-events: none;
-  display: inline;
-}
-
-.tab-view > li:before {
-  content: "";
-  pointer-events: none;
-  display: inline-block;
-  -moz-margin-end: .5rem;
-  vertical-align: middle;
-  height: 1.4rem;
-  width: 1.4rem;
-  transition-property: background-image;
-}
-
-.tab-view > li.selected {
-  transition-delay: .3s;
-}
-
-.tab-view > li[data-tab-name="rooms"]:before {
-  background-image: url("../shared/img/icons-14x14.svg#hello");
-}
-
-.tab-view > li[data-tab-name="rooms"]:hover:before {
-  background-image: url("../shared/img/icons-14x14.svg#hello-hover");
-}
-
-.tab-view > li[data-tab-name="rooms"].selected:before {
-  background-image: url("../shared/img/icons-14x14.svg#hello-active");
-}
-
-.tab-view > li[data-tab-name="contacts"]:before {
-  background-image: url("../shared/img/icons-14x14.svg#contacts");
-}
-
-.tab-view > li[data-tab-name="contacts"]:hover:before {
-  background-image: url("../shared/img/icons-14x14.svg#contacts-hover");
-}
-
-.tab-view > li[data-tab-name="contacts"].selected:before {
-  background-image: url("../shared/img/icons-14x14.svg#contacts-active");
-}
-
-/* Styling for one tab */
-.tab-view li:first-child:nth-last-child(2) {
-  width: 100%;
-}
-
-.tab-view li:first-child:nth-last-child(2) > span {
-  display: none;
-}
-
-.tab-view li:first-child:nth-last-child(2) > span {
-  display: none;
-}
-
-.tab-view li:first-child:nth-last-child(2):before {
-  background-image: url("../shared/img/icons-14x14.svg#hello-hover");
-}
-
-.tab-view li:first-child:nth-last-child(2) ~ li {
-  /* hide the tab-slider when there is only one tab shown */
-  display: none;
-}
-
-.tab-view li:first-child:nth-last-child(3),
-.tab-view li:first-child:nth-last-child(3) ~ li {
-  width: 50%;
-}
-
-.tab {
-  display: none;
-  flex: 1;
-  overflow: auto;
-}
-
-.tab.selected {
-  display: flex;
-  flex-flow: column nowrap;
-}
-
 /* Content area and input fields */
 
 .content-area {
   padding: .5rem 1rem;
 }
 
 .content-area header {
   font-weight: 700;
 }
 
 /* Need to remove when these rules when the Beta tag is removed */
 #share-link-header {
   -moz-padding-start: 20px;
 }
 
-.fte-get-started-container + .generate-url > #share-link-header,
-.tab-view + .tab .content-area > .generate-url > #share-link-header {
+.fte-get-started-container + .generate-url > #share-link-header {
   /* The header shouldn't be indented if the tabs are present. */
   -moz-padding-start: 0;
 }
 
 .content-area label {
   display: block;
   width: 100%;
   margin-top: 10px;
@@ -326,16 +184,17 @@ html[dir="rtl"] .tab-view li:nth-child(2
 }
 
 
 /* Rooms */
 .rooms {
   flex: 1;
   display: flex;
   flex-flow: column nowrap;
+  width: 100%;
 }
 
 .rooms > h1 {
   font-weight: bold;
   color: #666;
   padding: .5rem 0;
   height: 3rem;
   line-height: 3rem;
@@ -409,16 +268,17 @@ html[dir="rtl"] .tab-view li:nth-child(2
   /* xxx  not sure why flex needs the 3 value setting
     but setting flex to just 1, the whole tab including the new room is scrollable.
     seems to not like the 0% of the default setting - may be FF bug */
   flex: 1 1 0;
   overflow-y: auto;
   overflow-x: hidden;
   display: flex;
   flex-flow: column nowrap;
+  width: 100%;
 }
 
 .room-list-empty {
   border-bottom-width: 0;
   flex: 1;
   /* the child no-conversations-message is vertical aligned inside this container
     see: http://zerosixthree.se/vertical-align-anything-with-just-3-lines-of-css/
     stops blurring from decimal pixels being rendered - pixel rounding */
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -5,119 +5,18 @@
 var loop = loop || {};
 loop.panel = (function(_, mozL10n) {
   "use strict";
 
   var sharedViews = loop.shared.views;
   var sharedModels = loop.shared.models;
   var sharedMixins = loop.shared.mixins;
   var sharedActions = loop.shared.actions;
-  var sharedUtils = loop.shared.utils;
   var Button = sharedViews.Button;
-  var ButtonGroup = sharedViews.ButtonGroup;
   var Checkbox = sharedViews.Checkbox;
-  var ContactsControllerView = loop.contacts.ContactsControllerView;
-
-  var TabView = React.createClass({displayName: "TabView",
-    propTypes: {
-      buttonsHidden: React.PropTypes.array,
-      children: React.PropTypes.arrayOf(React.PropTypes.element),
-      mozLoop: React.PropTypes.object,
-      // The selectedTab prop is used by the UI showcase.
-      selectedTab: React.PropTypes.string
-    },
-
-    getDefaultProps: function() {
-      return {
-        buttonsHidden: []
-      };
-    },
-
-    shouldComponentUpdate: function(nextProps, nextState) {
-      var tabChange = this.state.selectedTab !== nextState.selectedTab;
-      if (tabChange) {
-        this.props.mozLoop.notifyUITour("Loop:PanelTabChanged", nextState.selectedTab);
-      }
-
-      if (!tabChange && nextProps.buttonsHidden) {
-        if (nextProps.buttonsHidden.length !== this.props.buttonsHidden.length) {
-          tabChange = true;
-        } else {
-          for (var i = 0, l = nextProps.buttonsHidden.length; i < l && !tabChange; ++i) {
-            if (this.props.buttonsHidden.indexOf(nextProps.buttonsHidden[i]) === -1) {
-              tabChange = true;
-            }
-          }
-        }
-      }
-      return tabChange;
-    },
-
-    getInitialState: function() {
-      // XXX Work around props.selectedTab being undefined initially.
-      // When we don't need to rely on the pref, this can move back to
-      // getDefaultProps (bug 1100258).
-      return {
-        selectedTab: this.props.selectedTab || "rooms"
-      };
-    },
-
-    handleSelectTab: function(event) {
-      var tabName = event.target.dataset.tabName;
-      this.setState({selectedTab: tabName});
-    },
-
-    render: function() {
-      var cx = React.addons.classSet;
-      var tabButtons = [];
-      var tabs = [];
-      React.Children.forEach(this.props.children, function(tab, i) {
-        // Filter out null tabs (eg. rooms when the feature is disabled)
-        if (!tab) {
-          return;
-        }
-        var tabName = tab.props.name;
-        if (this.props.buttonsHidden.indexOf(tabName) > -1) {
-          return;
-        }
-        var isSelected = (this.state.selectedTab === tabName);
-        if (!tab.props.hidden) {
-          var label = mozL10n.get(tabName + "_tab_button");
-          tabButtons.push(
-            React.createElement("li", {className: cx({selected: isSelected}), 
-                "data-tab-name": tabName, 
-                key: i, 
-                onClick: this.handleSelectTab}, 
-              React.createElement("div", null, label)
-            )
-          );
-        }
-        tabs.push(
-          React.createElement("div", {className: cx({tab: true, selected: isSelected}), key: i}, 
-            tab.props.children
-          )
-        );
-      }, this);
-      return (
-        React.createElement("div", {className: "tab-view-container"}, 
-          React.createElement("ul", {className: "tab-view"}, 
-            tabButtons, 
-            React.createElement("li", {className: "slide-bar"})
-          ), 
-          tabs
-        )
-      );
-    }
-  });
-
-  var Tab = React.createClass({displayName: "Tab",
-    render: function() {
-      return null;
-    }
-  });
 
   /**
    * Availability drop down menu subview.
    */
   var AvailabilityDropdown = React.createClass({displayName: "AvailabilityDropdown",
     mixins: [sharedMixins.DropdownMenuMixin()],
 
     getInitialState: function() {
@@ -764,19 +663,17 @@ loop.panel = (function(_, mozL10n) {
    * Room list.
    */
   var RoomList = React.createClass({displayName: "RoomList",
     mixins: [Backbone.Events, sharedMixins.WindowCloseMixin],
 
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       mozLoop: React.PropTypes.object.isRequired,
-      store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
-      // Used for room creation, associated with room owner.
-      userProfile: userProfileValidator
+      store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
     },
 
     getInitialState: function() {
       return this.props.store.getStoreState();
     },
 
     componentDidMount: function() {
       this.listenTo(this.props.store, "change", this._onStoreStateChanged);
@@ -799,21 +696,16 @@ loop.panel = (function(_, mozL10n) {
         this.closeWindow();
       }
     },
 
     _onStoreStateChanged: function() {
       this.setState(this.props.store.getStoreState());
     },
 
-    _getUserDisplayName: function() {
-      return this.props.userProfile && this.props.userProfile.email ||
-        mozL10n.get("display_name_guest");
-    },
-
     /**
      * Let the user know we're loading rooms
      * @returns {Object} React render
      */
     _renderLoadingRoomsView: function() {
       return (
         React.createElement("div", {className: "room-list"}, 
           React.createElement("div", {className: "room-list-loading"}, 
@@ -842,18 +734,17 @@ loop.panel = (function(_, mozL10n) {
       );
     },
 
     _renderNewRoomButton: function() {
       return (
         React.createElement(NewRoomView, {dispatcher: this.props.dispatcher, 
           mozLoop: this.props.mozLoop, 
           pendingOperation: this.state.pendingCreation ||
-                            this.state.pendingInitialRetrieval, 
-          userDisplayName: this._getUserDisplayName()})
+                            this.state.pendingInitialRetrieval})
       );
     },
 
     render: function() {
       if (this.state.error) {
         // XXX Better end user reporting of errors.
         console.error("RoomList error", this.state.error);
       }
@@ -888,18 +779,17 @@ loop.panel = (function(_, mozL10n) {
 
   /**
    * Used for creating a new room with or without context.
    */
   var NewRoomView = React.createClass({displayName: "NewRoomView",
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       mozLoop: React.PropTypes.object.isRequired,
-      pendingOperation: React.PropTypes.bool.isRequired,
-      userDisplayName: React.PropTypes.string.isRequired
+      pendingOperation: React.PropTypes.bool.isRequired
     },
 
     mixins: [
       sharedMixins.DocumentVisibilityMixin,
       React.addons.PureRenderMixin
     ],
 
     getInitialState: function() {
@@ -996,24 +886,20 @@ loop.panel = (function(_, mozL10n) {
   });
 
   /**
    * Panel view.
    */
   var PanelView = React.createClass({displayName: "PanelView",
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
-      initialSelectedTabComponent: React.PropTypes.string,
       mozLoop: React.PropTypes.object.isRequired,
       notifications: React.PropTypes.object.isRequired,
       roomStore:
-        React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
-      selectedTab: React.PropTypes.string,
-      // Used only for unit tests.
-      showTabButtons: React.PropTypes.bool
+        React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
     },
 
     getInitialState: function() {
       return {
         hasEncryptionKey: this.props.mozLoop.hasEncryptionKey,
         userProfile: this.props.mozLoop.userProfile,
         gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen")
       };
@@ -1051,62 +937,39 @@ loop.panel = (function(_, mozL10n) {
     _onStatusChanged: function() {
       var profile = this.props.mozLoop.userProfile;
       var currUid = this.state.userProfile ? this.state.userProfile.uid : null;
       var newUid = profile ? profile.uid : null;
       if (currUid === newUid) {
         // Update the state of hasEncryptionKey as this might have changed now.
         this.setState({hasEncryptionKey: this.props.mozLoop.hasEncryptionKey});
       } else {
-        // On profile change (login, logout), switch back to the default tab.
-        this.selectTab("rooms");
         this.setState({userProfile: profile});
       }
       this.updateServiceErrors();
     },
 
     _gettingStartedSeen: function() {
       this.setState({
         gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen")
       });
     },
 
-    _UIActionHandler: function(e) {
-      switch (e.detail.action) {
-        case "selectTab":
-          this.selectTab(e.detail.tab);
-          break;
-        default:
-          console.error("Invalid action", e.detail.action);
-          break;
-      }
-    },
-
-    selectTab: function(name) {
-      // The tab view might not be created yet (e.g. getting started or fxa
-      // re-sign in.
-      if (this.refs.tabView) {
-        this.refs.tabView.setState({ selectedTab: name });
-      }
-    },
-
     componentWillMount: function() {
       this.updateServiceErrors();
     },
 
     componentDidMount: function() {
       window.addEventListener("LoopStatusChanged", this._onStatusChanged);
       window.addEventListener("GettingStartedSeen", this._gettingStartedSeen);
-      window.addEventListener("UIAction", this._UIActionHandler);
     },
 
     componentWillUnmount: function() {
       window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
       window.removeEventListener("GettingStartedSeen", this._gettingStartedSeen);
-      window.removeEventListener("UIAction", this._UIActionHandler);
     },
 
     render: function() {
       var NotificationListView = sharedViews.NotificationListView;
 
       if (!this.state.gettingStartedSeen) {
         return (
           React.createElement("div", {className: "fte-get-started-container"}, 
@@ -1118,45 +981,24 @@ loop.panel = (function(_, mozL10n) {
           )
         );
       }
 
       if (!this.state.hasEncryptionKey) {
         return React.createElement(SignInRequestView, {mozLoop: this.props.mozLoop});
       }
 
-      // Determine which buttons to NOT show.
-      var hideButtons = [];
-      if (!this.state.userProfile && !this.props.showTabButtons) {
-        hideButtons.push("contacts");
-      }
-
       return (
         React.createElement("div", {className: "panel-content"}, 
           React.createElement(NotificationListView, {
             clearOnDocumentHidden: true, 
             notifications: this.props.notifications}), 
-          React.createElement(TabView, {
-            buttonsHidden: hideButtons, 
-            mozLoop: this.props.mozLoop, 
-            ref: "tabView", 
-            selectedTab: this.props.selectedTab}, 
-            React.createElement(Tab, {name: "rooms"}, 
-              React.createElement(RoomList, {dispatcher: this.props.dispatcher, 
-                        mozLoop: this.props.mozLoop, 
-                        store: this.props.roomStore, 
-                        userProfile: this.state.userProfile})
-            ), 
-            React.createElement(Tab, {name: "contacts"}, 
-              React.createElement(ContactsControllerView, {initialSelectedTabComponent: this.props.initialSelectedTabComponent, 
-                                      mozLoop: this.props.mozLoop, 
-                                      notifications: this.props.notifications, 
-                                      ref: "contactControllerView"})
-            )
-          ), 
+            React.createElement(RoomList, {dispatcher: this.props.dispatcher, 
+                      mozLoop: this.props.mozLoop, 
+                      store: this.props.roomStore}), 
           React.createElement("div", {className: "footer"}, 
             React.createElement("div", {className: "user-details"}, 
               React.createElement(AvailabilityDropdown, null)
             ), 
             React.createElement("div", {className: "signin-details"}, 
               React.createElement(AccountLink, {fxAEnabled: this.props.mozLoop.fxAEnabled, 
                            userProfile: this.state.userProfile}), 
               React.createElement(SettingsDropdown, {mozLoop: this.props.mozLoop})
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -5,119 +5,18 @@
 var loop = loop || {};
 loop.panel = (function(_, mozL10n) {
   "use strict";
 
   var sharedViews = loop.shared.views;
   var sharedModels = loop.shared.models;
   var sharedMixins = loop.shared.mixins;
   var sharedActions = loop.shared.actions;
-  var sharedUtils = loop.shared.utils;
   var Button = sharedViews.Button;
-  var ButtonGroup = sharedViews.ButtonGroup;
   var Checkbox = sharedViews.Checkbox;
-  var ContactsControllerView = loop.contacts.ContactsControllerView;
-
-  var TabView = React.createClass({
-    propTypes: {
-      buttonsHidden: React.PropTypes.array,
-      children: React.PropTypes.arrayOf(React.PropTypes.element),
-      mozLoop: React.PropTypes.object,
-      // The selectedTab prop is used by the UI showcase.
-      selectedTab: React.PropTypes.string
-    },
-
-    getDefaultProps: function() {
-      return {
-        buttonsHidden: []
-      };
-    },
-
-    shouldComponentUpdate: function(nextProps, nextState) {
-      var tabChange = this.state.selectedTab !== nextState.selectedTab;
-      if (tabChange) {
-        this.props.mozLoop.notifyUITour("Loop:PanelTabChanged", nextState.selectedTab);
-      }
-
-      if (!tabChange && nextProps.buttonsHidden) {
-        if (nextProps.buttonsHidden.length !== this.props.buttonsHidden.length) {
-          tabChange = true;
-        } else {
-          for (var i = 0, l = nextProps.buttonsHidden.length; i < l && !tabChange; ++i) {
-            if (this.props.buttonsHidden.indexOf(nextProps.buttonsHidden[i]) === -1) {
-              tabChange = true;
-            }
-          }
-        }
-      }
-      return tabChange;
-    },
-
-    getInitialState: function() {
-      // XXX Work around props.selectedTab being undefined initially.
-      // When we don't need to rely on the pref, this can move back to
-      // getDefaultProps (bug 1100258).
-      return {
-        selectedTab: this.props.selectedTab || "rooms"
-      };
-    },
-
-    handleSelectTab: function(event) {
-      var tabName = event.target.dataset.tabName;
-      this.setState({selectedTab: tabName});
-    },
-
-    render: function() {
-      var cx = React.addons.classSet;
-      var tabButtons = [];
-      var tabs = [];
-      React.Children.forEach(this.props.children, function(tab, i) {
-        // Filter out null tabs (eg. rooms when the feature is disabled)
-        if (!tab) {
-          return;
-        }
-        var tabName = tab.props.name;
-        if (this.props.buttonsHidden.indexOf(tabName) > -1) {
-          return;
-        }
-        var isSelected = (this.state.selectedTab === tabName);
-        if (!tab.props.hidden) {
-          var label = mozL10n.get(tabName + "_tab_button");
-          tabButtons.push(
-            <li className={cx({selected: isSelected})}
-                data-tab-name={tabName}
-                key={i}
-                onClick={this.handleSelectTab}>
-              <div>{label}</div>
-            </li>
-          );
-        }
-        tabs.push(
-          <div className={cx({tab: true, selected: isSelected})} key={i}>
-            {tab.props.children}
-          </div>
-        );
-      }, this);
-      return (
-        <div className="tab-view-container">
-          <ul className="tab-view">
-            {tabButtons}
-            <li className="slide-bar" />
-          </ul>
-          {tabs}
-        </div>
-      );
-    }
-  });
-
-  var Tab = React.createClass({
-    render: function() {
-      return null;
-    }
-  });
 
   /**
    * Availability drop down menu subview.
    */
   var AvailabilityDropdown = React.createClass({
     mixins: [sharedMixins.DropdownMenuMixin()],
 
     getInitialState: function() {
@@ -764,19 +663,17 @@ loop.panel = (function(_, mozL10n) {
    * Room list.
    */
   var RoomList = React.createClass({
     mixins: [Backbone.Events, sharedMixins.WindowCloseMixin],
 
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       mozLoop: React.PropTypes.object.isRequired,
-      store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
-      // Used for room creation, associated with room owner.
-      userProfile: userProfileValidator
+      store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
     },
 
     getInitialState: function() {
       return this.props.store.getStoreState();
     },
 
     componentDidMount: function() {
       this.listenTo(this.props.store, "change", this._onStoreStateChanged);
@@ -799,21 +696,16 @@ loop.panel = (function(_, mozL10n) {
         this.closeWindow();
       }
     },
 
     _onStoreStateChanged: function() {
       this.setState(this.props.store.getStoreState());
     },
 
-    _getUserDisplayName: function() {
-      return this.props.userProfile && this.props.userProfile.email ||
-        mozL10n.get("display_name_guest");
-    },
-
     /**
      * Let the user know we're loading rooms
      * @returns {Object} React render
      */
     _renderLoadingRoomsView: function() {
       return (
         <div className="room-list">
           <div className="room-list-loading">
@@ -842,18 +734,17 @@ loop.panel = (function(_, mozL10n) {
       );
     },
 
     _renderNewRoomButton: function() {
       return (
         <NewRoomView dispatcher={this.props.dispatcher}
           mozLoop={this.props.mozLoop}
           pendingOperation={this.state.pendingCreation ||
-                            this.state.pendingInitialRetrieval}
-          userDisplayName={this._getUserDisplayName()} />
+                            this.state.pendingInitialRetrieval} />
       );
     },
 
     render: function() {
       if (this.state.error) {
         // XXX Better end user reporting of errors.
         console.error("RoomList error", this.state.error);
       }
@@ -888,18 +779,17 @@ loop.panel = (function(_, mozL10n) {
 
   /**
    * Used for creating a new room with or without context.
    */
   var NewRoomView = React.createClass({
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       mozLoop: React.PropTypes.object.isRequired,
-      pendingOperation: React.PropTypes.bool.isRequired,
-      userDisplayName: React.PropTypes.string.isRequired
+      pendingOperation: React.PropTypes.bool.isRequired
     },
 
     mixins: [
       sharedMixins.DocumentVisibilityMixin,
       React.addons.PureRenderMixin
     ],
 
     getInitialState: function() {
@@ -996,24 +886,20 @@ loop.panel = (function(_, mozL10n) {
   });
 
   /**
    * Panel view.
    */
   var PanelView = React.createClass({
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
-      initialSelectedTabComponent: React.PropTypes.string,
       mozLoop: React.PropTypes.object.isRequired,
       notifications: React.PropTypes.object.isRequired,
       roomStore:
-        React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
-      selectedTab: React.PropTypes.string,
-      // Used only for unit tests.
-      showTabButtons: React.PropTypes.bool
+        React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
     },
 
     getInitialState: function() {
       return {
         hasEncryptionKey: this.props.mozLoop.hasEncryptionKey,
         userProfile: this.props.mozLoop.userProfile,
         gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen")
       };
@@ -1051,62 +937,39 @@ loop.panel = (function(_, mozL10n) {
     _onStatusChanged: function() {
       var profile = this.props.mozLoop.userProfile;
       var currUid = this.state.userProfile ? this.state.userProfile.uid : null;
       var newUid = profile ? profile.uid : null;
       if (currUid === newUid) {
         // Update the state of hasEncryptionKey as this might have changed now.
         this.setState({hasEncryptionKey: this.props.mozLoop.hasEncryptionKey});
       } else {
-        // On profile change (login, logout), switch back to the default tab.
-        this.selectTab("rooms");
         this.setState({userProfile: profile});
       }
       this.updateServiceErrors();
     },
 
     _gettingStartedSeen: function() {
       this.setState({
         gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen")
       });
     },
 
-    _UIActionHandler: function(e) {
-      switch (e.detail.action) {
-        case "selectTab":
-          this.selectTab(e.detail.tab);
-          break;
-        default:
-          console.error("Invalid action", e.detail.action);
-          break;
-      }
-    },
-
-    selectTab: function(name) {
-      // The tab view might not be created yet (e.g. getting started or fxa
-      // re-sign in.
-      if (this.refs.tabView) {
-        this.refs.tabView.setState({ selectedTab: name });
-      }
-    },
-
     componentWillMount: function() {
       this.updateServiceErrors();
     },
 
     componentDidMount: function() {
       window.addEventListener("LoopStatusChanged", this._onStatusChanged);
       window.addEventListener("GettingStartedSeen", this._gettingStartedSeen);
-      window.addEventListener("UIAction", this._UIActionHandler);
     },
 
     componentWillUnmount: function() {
       window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
       window.removeEventListener("GettingStartedSeen", this._gettingStartedSeen);
-      window.removeEventListener("UIAction", this._UIActionHandler);
     },
 
     render: function() {
       var NotificationListView = sharedViews.NotificationListView;
 
       if (!this.state.gettingStartedSeen) {
         return (
           <div className="fte-get-started-container">
@@ -1118,45 +981,24 @@ loop.panel = (function(_, mozL10n) {
           </div>
         );
       }
 
       if (!this.state.hasEncryptionKey) {
         return <SignInRequestView mozLoop={this.props.mozLoop} />;
       }
 
-      // Determine which buttons to NOT show.
-      var hideButtons = [];
-      if (!this.state.userProfile && !this.props.showTabButtons) {
-        hideButtons.push("contacts");
-      }
-
       return (
         <div className="panel-content">
           <NotificationListView
             clearOnDocumentHidden={true}
             notifications={this.props.notifications} />
-          <TabView
-            buttonsHidden={hideButtons}
-            mozLoop={this.props.mozLoop}
-            ref="tabView"
-            selectedTab={this.props.selectedTab}>
-            <Tab name="rooms">
-              <RoomList dispatcher={this.props.dispatcher}
-                        mozLoop={this.props.mozLoop}
-                        store={this.props.roomStore}
-                        userProfile={this.state.userProfile} />
-            </Tab>
-            <Tab name="contacts">
-              <ContactsControllerView initialSelectedTabComponent={this.props.initialSelectedTabComponent}
-                                      mozLoop={this.props.mozLoop}
-                                      notifications={this.props.notifications}
-                                      ref="contactControllerView" />
-            </Tab>
-          </TabView>
+            <RoomList dispatcher={this.props.dispatcher}
+                      mozLoop={this.props.mozLoop}
+                      store={this.props.roomStore} />
           <div className="footer">
             <div className="user-details">
               <AvailabilityDropdown />
             </div>
             <div className="signin-details">
               <AccountLink fxAEnabled={this.props.mozLoop.fxAEnabled}
                            userProfile={this.state.userProfile}/>
               <SettingsDropdown mozLoop={this.props.mozLoop}/>
--- a/browser/components/loop/content/shared/css/conversation.css
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -1107,17 +1107,17 @@ body[platform="win"] .share-service-drop
   }
 
   .media-wrapper.receiving-screen-share > .text-chat-view {
     order: 4;
   }
 }
 
 /* e.g. very narrow widths similar to conversation window */
-@media screen and (max-width:300px) {
+@media screen and (max-width:350px) {
   .media-layout > .media-wrapper {
     flex-flow: column nowrap;
   }
 
   .media-wrapper > .focus-stream > .local ~ .conversation-toolbar {
     max-width: calc(75% - 22px);
   }
 
@@ -1434,17 +1434,17 @@ html[dir="rtl"] .text-chat-entry.receive
     width: 100%;
   }
   .standalone .room-conversation .video_wrapper.remote_wrapper.not-joined {
     width: 100%;
   }
 }
 
 /* e.g. very narrow widths similar to conversation window */
-@media screen and (max-width:300px) {
+@media screen and (max-width:350px) {
   .text-chat-view {
     display: flex;
     flex-flow: column nowrap;
     /* 120px max-height of .text-chat-entries plus 40px of .text-chat-box */
     max-height: 160px;
     /* 60px min-height of .text-chat-entries plus 40px of .text-chat-box */
     min-height: 100px;
     height: auto;
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -205,79 +205,16 @@ describe("loop.panel", function() {
         React.createElement(loop.panel.SettingsDropdown, {
           mozLoop: fakeMozLoop
         }));
 
       expect(view.getDOMNode().querySelectorAll(".icon-account"))
         .to.have.length.of(0);
     });
 
-    describe("TabView", function() {
-      var view, callTab, roomsTab, contactsTab;
-
-      beforeEach(function() {
-        navigator.mozLoop.getLoopPref = function(pref) {
-          if (pref === "gettingStarted.seen") {
-            return true;
-          }
-        };
-
-        view = createTestPanelView();
-
-        [roomsTab, contactsTab] =
-          TestUtils.scryRenderedDOMComponentsWithClass(view, "tab");
-      });
-
-      it("should select contacts tab when clicking tab button", function() {
-        TestUtils.Simulate.click(
-          view.getDOMNode().querySelector("li[data-tab-name=\"contacts\"]"));
-
-        expect(contactsTab.getDOMNode().classList.contains("selected"))
-          .to.be.true;
-      });
-
-      it("should select rooms tab when clicking tab button", function() {
-        TestUtils.Simulate.click(
-          view.getDOMNode().querySelector("li[data-tab-name=\"rooms\"]"));
-
-        expect(roomsTab.getDOMNode().classList.contains("selected"))
-          .to.be.true;
-      });
-    });
-
-    describe("Contacts", function() {
-      var view, roomsTab, contactsTab;
-
-      beforeEach(function() {
-        view = TestUtils.renderIntoDocument(
-          React.createElement(loop.panel.PanelView, {
-            dispatcher: dispatcher,
-            initialSelectedTabComponent: "contactList",
-            mozLoop: navigator.mozLoop,
-            notifications: notifications,
-            roomStore: roomStore,
-            selectedTab: "contacts",
-            showTabButtons: true
-          }));
-
-        [roomsTab, contactsTab] =
-          TestUtils.scryRenderedDOMComponentsWithClass(view, "tab");
-      });
-
-      it("should expect Contacts tab to be selected when Contacts List displayed", function() {
-        expect(contactsTab.getDOMNode().classList.contains("selected"))
-          .to.be.true;
-      });
-
-      it("should expect Rooms tab to be not selected when Contacts List displayed", function() {
-        expect(roomsTab.getDOMNode().classList.contains("selected"))
-          .to.be.false;
-      });
-    });
-
     describe("AccountLink", function() {
       beforeEach(function() {
         navigator.mozLoop.calls = { clearCallInProgress: function() {} };
       });
 
       afterEach(function() {
         delete navigator.mozLoop.logInToFxA;
         delete navigator.mozLoop.calls;
--- a/browser/components/loop/test/mochitest/browser_toolbarbutton.js
+++ b/browser/components/loop/test/mochitest/browser_toolbarbutton.js
@@ -27,55 +27,23 @@ registerCleanupFunction(function*() {
   MozLoopServiceInternal.fxAOAuthProfile = null;
   yield MozLoopServiceInternal.clearError("testing");
   Services.prefs.clearUserPref("loop.gettingStarted.seen");
 });
 
 add_task(function* test_LoopUI_getters() {
   Assert.ok(LoopUI.panel, "LoopUI panel element should be set");
   Assert.strictEqual(LoopUI.browser, null, "Browser element should not be there yet");
-  Assert.strictEqual(LoopUI.selectedTab, null, "No tab should be selected yet");
 
   // Load and show the Loop panel for the very first time this session.
   yield loadLoopPanel();
   Assert.ok(LoopUI.browser, "Browser element should be there");
-  Assert.strictEqual(LoopUI.selectedTab, "rooms", "Initially the rooms tab should be selected");
-  let panelTabs = LoopUI.browser.contentDocument.querySelectorAll(".tab-view > li:not(.slide-bar)");
-  Assert.strictEqual(panelTabs.length, 1, "Only one tab, 'rooms', should be visible");
 
   // Hide the panel.
   yield LoopUI.togglePanel();
-  Assert.strictEqual(LoopUI.selectedTab, "rooms", "Rooms tab should still be selected");
-
-  // Make sure the contacts tab shows up by simulating a login.
-  MozLoopServiceInternal.fxAOAuthTokenData = fxASampleToken;
-  MozLoopServiceInternal.fxAOAuthProfile = fxASampleProfile;
-  yield MozLoopServiceInternal.notifyStatusChanged("login");
-
-  yield LoopUI.togglePanel();
-  Assert.strictEqual(LoopUI.selectedTab, "rooms", "Rooms tab should still be selected");
-  panelTabs = LoopUI.browser.contentDocument.querySelectorAll(".tab-view > li:not(.slide-bar)");
-  Assert.strictEqual(panelTabs.length, 2, "Two tabs should be visible");
-  yield LoopUI.togglePanel();
-
-  // Programmatically select the contacts tab.
-  yield LoopUI.togglePanel(null, "contacts");
-  Assert.strictEqual(LoopUI.selectedTab, "contacts", "Contacts tab should be selected now");
-
-  // Switch back to the rooms tab.
-  yield LoopUI.openCallPanel(null, "rooms");
-  Assert.strictEqual(LoopUI.selectedTab, "rooms", "Rooms tab should be selected now");
-
-  // Hide the panel.
-  yield LoopUI.togglePanel();
-
-  // Logout to prevent interfering with the tests after this one.
-  MozLoopServiceInternal.fxAOAuthTokenData =
-    MozLoopServiceInternal.fxAOAuthProfile = null;
-  yield MozLoopServiceInternal.notifyStatusChanged();
 });
 
 add_task(function* test_doNotDisturb() {
   Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
   yield MozLoopService.doNotDisturb = true;
   Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "disabled", "Check button is in disabled state");
   yield MozLoopService.doNotDisturb = false;
   Assert.notStrictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "disabled", "Check button is not in disabled state");
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -761,103 +761,97 @@
                            height: 410, 
                            summary: "First time experience view", 
                            width: 330}, 
               React.createElement("div", {className: "panel"}, 
                 React.createElement(PanelView, {client: mockClient, 
                   dispatcher: dispatcher, 
                   mozLoop: firstTimeUseMozLoop, 
                   notifications: notifications, 
-                  roomStore: roomStore, 
-                  selectedTab: "rooms"})
+                  roomStore: roomStore})
               )
             ), 
 
             React.createElement(FramedExample, {cssClass: "fx-embedded-panel", 
               dashed: true, 
               height: 410, 
               summary: "Re-sign-in view", 
               width: 332}, 
               React.createElement("div", {className: "panel"}, 
                 React.createElement(SignInRequestView, {mozLoop: mockMozLoopLoggedIn})
               )
             ), 
 
             React.createElement(FramedExample, {cssClass: "fx-embedded-panel", 
                            dashed: true, 
                            height: 410, 
-                           summary: "Room list tab", 
+                           summary: "Room list", 
                            width: 330}, 
               React.createElement("div", {className: "panel"}, 
                 React.createElement(PanelView, {client: mockClient, 
                            dispatcher: dispatcher, 
                            mozLoop: mockMozLoopLoggedIn, 
                            notifications: notifications, 
-                           roomStore: roomStore, 
-                           selectedTab: "rooms"})
+                           roomStore: roomStore})
               )
             ), 
 
             React.createElement(FramedExample, {cssClass: "fx-embedded-panel", 
                            dashed: true, 
                            height: 410, 
-                           summary: "Room list tab (No Context)", 
+                           summary: "Room list (No Context)", 
                            width: 330}, 
               React.createElement("div", {className: "panel"}, 
                 React.createElement(PanelView, {client: mockClient, 
                            dispatcher: dispatcher, 
                            mozLoop: mockMozLoopLoggedInNoContext, 
                            notifications: notifications, 
-                           roomStore: roomStore, 
-                           selectedTab: "rooms"})
+                           roomStore: roomStore})
               )
             ), 
 
             React.createElement(FramedExample, {cssClass: "fx-embedded-panel", 
                            dashed: true, 
                            height: 410, 
-                           summary: "Room list tab (no rooms)", 
+                           summary: "Room list (no rooms)", 
                            width: 330}, 
               React.createElement("div", {className: "panel"}, 
                 React.createElement(PanelView, {client: mockClient, 
                            dispatcher: dispatcher, 
                            mozLoop: mockMozLoopNoRooms, 
                            notifications: notifications, 
-                           roomStore: roomStoreNoRooms, 
-                           selectedTab: "rooms"})
+                           roomStore: roomStoreNoRooms})
               )
             ), 
 
             React.createElement(FramedExample, {cssClass: "fx-embedded-panel", 
                            dashed: true, 
                            height: 410, 
-                           summary: "Room list tab (no rooms and no context)", 
+                           summary: "Room list (no rooms and no context)", 
                            width: 330}, 
               React.createElement("div", {className: "panel"}, 
                 React.createElement(PanelView, {client: mockClient, 
                            dispatcher: dispatcher, 
                            mozLoop: mockMozLoopNoRoomsNoContext, 
                            notifications: notifications, 
-                           roomStore: roomStoreNoRooms, 
-                           selectedTab: "rooms"})
+                           roomStore: roomStoreNoRooms})
               )
             ), 
 
             React.createElement(FramedExample, {cssClass: "fx-embedded-panel", 
                            dashed: true, 
                            height: 410, 
-                           summary: "Room list tab (loading view)", 
+                           summary: "Room list (loading view)", 
                            width: 330}, 
               React.createElement("div", {className: "panel"}, 
                 React.createElement(PanelView, {client: mockClient, 
                            dispatcher: dispatcher, 
                            mozLoop: mockMozLoopNoRoomsNoContext, 
                            notifications: notifications, 
-                           roomStore: roomStoreNoRoomsPending, 
-                           selectedTab: "rooms"})
+                           roomStore: roomStoreNoRoomsPending})
               )
             ), 
 
             React.createElement(FramedExample, {cssClass: "fx-embedded-panel", 
                            dashed: true, 
                            height: 410, 
                            summary: "Contact list tab", 
                            width: 330}, 
@@ -1210,20 +1204,20 @@
                   mozLoop: navigator.mozLoop, 
                   outgoing: true})
               )
             )
           ), 
 
           React.createElement(Section, {name: "OngoingConversationView"}, 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 394, 
+                           height: 398, 
                            onContentsRendered: conversationStores[0].forcedUpdate, 
                            summary: "Desktop ongoing conversation window", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(OngoingConversationView, {
                   audio: { enabled: true, visible: true}, 
                   chatWindowDetached: false, 
                   conversationStore: conversationStores[0], 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mediaConnected: true, 
@@ -1266,39 +1260,39 @@
                   mediaConnected: true, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
                   remoteVideoEnabled: true, 
                   video: { enabled: true, visible: true}})
               )
             ), 
 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 394, 
+                           height: 398, 
                            onContentsRendered: conversationStores[3].forcedUpdate, 
                            summary: "Desktop ongoing conversation window - local face mute", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(OngoingConversationView, {
                   audio: { enabled: true, visible: true}, 
                   chatWindowDetached: false, 
                   conversationStore: conversationStores[3], 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mediaConnected: true, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
                   remoteVideoEnabled: true, 
                   video: { enabled: false, visible: true}})
               )
             ), 
 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 394, 
+                           height: 398, 
                            onContentsRendered: conversationStores[4].forcedUpdate, 
                            summary: "Desktop ongoing conversation window - remote face mute", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(OngoingConversationView, {
                   audio: { enabled: true, visible: true}, 
                   chatWindowDetached: false, 
                   conversationStore: conversationStores[4], 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mediaConnected: true, 
@@ -1309,31 +1303,31 @@
             )
 
           ), 
 
           React.createElement(Section, {name: "FeedbackView"}, 
             React.createElement("p", {className: "note"}
             ), 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 272, 
+                           height: 288, 
                            summary: "Default (useable demo)", 
-                           width: 300}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(FeedbackView, {mozLoop: {}, 
                               onAfterFeedbackReceived: function() {}})
               )
             )
           ), 
 
           React.createElement(Section, {name: "AlertMessages"}, 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 272, 
+                           height: 288, 
                            summary: "Various alerts", 
-                           width: 300}, 
+                           width: 348}, 
               React.createElement("div", null, 
                 React.createElement("div", {className: "alert alert-warning"}, 
                   React.createElement("button", {className: "close"}), 
                   React.createElement("p", {className: "message"}, 
                     "The person you were calling has ended the conversation."
                   )
                 ), 
                 React.createElement("br", null), 
@@ -1369,87 +1363,87 @@
                 React.createElement(UnsupportedDeviceView, {platform: "ios"})
               )
             )
           ), 
 
           React.createElement(Section, {name: "RoomFailureView"}, 
             React.createElement(FramedExample, {
               dashed: true, 
-              height: 254, 
+              height: 288, 
               summary: "Desktop Room Failure View", 
-              width: 298}, 
+              width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(RoomFailureView, {
                   dispatcher: dispatcher, 
                   failureReason: FAILURE_DETAILS.UNKNOWN, 
                   mozLoop: navigator.mozLoop})
               )
             )
           ), 
 
           React.createElement(Section, {name: "DesktopRoomConversationView"}, 
             React.createElement(FramedExample, {height: 398, 
                            onContentsRendered: invitationRoomStore.activeRoomStore.forcedUpdate, 
                            summary: "Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(DesktopRoomConversationView, {
                   chatWindowDetached: false, 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mozLoop: navigator.mozLoop, 
                   onCallTerminated: function(){}, 
                   roomState: ROOM_STATES.INIT, 
                   roomStore: invitationRoomStore})
               )
             ), 
 
-            React.createElement(FramedExample, {height: 278.6, 
+            React.createElement(FramedExample, {height: 288, 
                            onContentsRendered: invitationRoomStore.activeRoomStore.forcedUpdate, 
                            summary: "Desktop room Edit Context w/Error", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded room-invitation-overlay"}, 
                 React.createElement(DesktopRoomEditContextView, {
                   dispatcher: dispatcher, 
                   error: {}, 
                   mozLoop: navigator.mozLoop, 
                   onClose: function(){}, 
                   roomData: {}, 
                   savingContext: false, 
                   show: true}
                   )
               )
             ), 
 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 394, 
+                           height: 398, 
                            onContentsRendered: desktopRoomStoreLoading.activeRoomStore.forcedUpdate, 
                            summary: "Desktop room conversation (loading)", 
-                           width: 298}, 
+                           width: 348}, 
               /* Hide scrollbars here. Rotating loading div overflows and causes
                scrollbars to appear */
               React.createElement("div", {className: "fx-embedded overflow-hidden"}, 
                 React.createElement(DesktopRoomConversationView, {
                   chatWindowDetached: false, 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mozLoop: navigator.mozLoop, 
                   onCallTerminated: function(){}, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
                   roomState: ROOM_STATES.HAS_PARTICIPANTS, 
                   roomStore: desktopRoomStoreLoading})
               )
             ), 
 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 394, 
+                           height: 398, 
                            onContentsRendered: roomStore.activeRoomStore.forcedUpdate, 
                            summary: "Desktop room conversation", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(DesktopRoomConversationView, {
                   chatWindowDetached: false, 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mozLoop: navigator.mozLoop, 
                   onCallTerminated: function(){}, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
@@ -1490,36 +1484,36 @@
                   onCallTerminated: function(){}, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
                   roomState: ROOM_STATES.HAS_PARTICIPANTS, 
                   roomStore: desktopRoomStoreLarge})
               )
             ), 
 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 394, 
+                           height: 398, 
                            onContentsRendered: desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate, 
                            summary: "Desktop room conversation local face-mute", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(DesktopRoomConversationView, {
                   chatWindowDetached: false, 
                   dispatcher: dispatcher, 
                   mozLoop: navigator.mozLoop, 
                   onCallTerminated: function(){}, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
                   roomStore: desktopLocalFaceMuteRoomStore})
               )
             ), 
 
             React.createElement(FramedExample, {dashed: true, 
-                           height: 394, 
+                           height: 398, 
                            onContentsRendered: desktopRemoteFaceMuteRoomStore.activeRoomStore.forcedUpdate, 
                            summary: "Desktop room conversation remote face-mute", 
-                           width: 298}, 
+                           width: 348}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(DesktopRoomConversationView, {
                   chatWindowDetached: false, 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mozLoop: navigator.mozLoop, 
                   onCallTerminated: function(){}, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -761,103 +761,97 @@
                            height={410}
                            summary="First time experience view"
                            width={330}>
               <div className="panel">
                 <PanelView client={mockClient}
                   dispatcher={dispatcher}
                   mozLoop={firstTimeUseMozLoop}
                   notifications={notifications}
-                  roomStore={roomStore}
-                  selectedTab="rooms" />
+                  roomStore={roomStore} />
               </div>
             </FramedExample>
 
             <FramedExample cssClass="fx-embedded-panel"
               dashed={true}
               height={410}
               summary="Re-sign-in view"
               width={332}>
               <div className="panel">
                 <SignInRequestView mozLoop={mockMozLoopLoggedIn} />
               </div>
             </FramedExample>
 
             <FramedExample cssClass="fx-embedded-panel"
                            dashed={true}
                            height={410}
-                           summary="Room list tab"
+                           summary="Room list"
                            width={330}>
               <div className="panel">
                 <PanelView client={mockClient}
                            dispatcher={dispatcher}
                            mozLoop={mockMozLoopLoggedIn}
                            notifications={notifications}
-                           roomStore={roomStore}
-                           selectedTab="rooms" />
+                           roomStore={roomStore} />
               </div>
             </FramedExample>
 
             <FramedExample cssClass="fx-embedded-panel"
                            dashed={true}
                            height={410}
-                           summary="Room list tab (No Context)"
+                           summary="Room list (No Context)"
                            width={330}>
               <div className="panel">
                 <PanelView client={mockClient}
                            dispatcher={dispatcher}
                            mozLoop={mockMozLoopLoggedInNoContext}
                            notifications={notifications}
-                           roomStore={roomStore}
-                           selectedTab="rooms" />
+                           roomStore={roomStore} />
               </div>
             </FramedExample>
 
             <FramedExample cssClass="fx-embedded-panel"
                            dashed={true}
                            height={410}
-                           summary="Room list tab (no rooms)"
+                           summary="Room list (no rooms)"
                            width={330}>
               <div className="panel">
                 <PanelView client={mockClient}
                            dispatcher={dispatcher}
                            mozLoop={mockMozLoopNoRooms}
                            notifications={notifications}
-                           roomStore={roomStoreNoRooms}
-                           selectedTab="rooms" />
+                           roomStore={roomStoreNoRooms} />
               </div>
             </FramedExample>
 
             <FramedExample cssClass="fx-embedded-panel"
                            dashed={true}
                            height={410}
-                           summary="Room list tab (no rooms and no context)"
+                           summary="Room list (no rooms and no context)"
                            width={330}>
               <div className="panel">
                 <PanelView client={mockClient}
                            dispatcher={dispatcher}
                            mozLoop={mockMozLoopNoRoomsNoContext}
                            notifications={notifications}
-                           roomStore={roomStoreNoRooms}
-                           selectedTab="rooms" />
+                           roomStore={roomStoreNoRooms} />
               </div>
             </FramedExample>
 
             <FramedExample cssClass="fx-embedded-panel"
                            dashed={true}
                            height={410}
-                           summary="Room list tab (loading view)"
+                           summary="Room list (loading view)"
                            width={330}>
               <div className="panel">
                 <PanelView client={mockClient}
                            dispatcher={dispatcher}
                            mozLoop={mockMozLoopNoRoomsNoContext}
                            notifications={notifications}
-                           roomStore={roomStoreNoRoomsPending}
-                           selectedTab="rooms" />
+                           roomStore={roomStoreNoRoomsPending} />
               </div>
             </FramedExample>
 
             <FramedExample cssClass="fx-embedded-panel"
                            dashed={true}
                            height={410}
                            summary="Contact list tab"
                            width={330}>
@@ -1210,20 +1204,20 @@
                   mozLoop={navigator.mozLoop}
                   outgoing={true} />
               </div>
             </FramedExample>
           </Section>
 
           <Section name="OngoingConversationView">
             <FramedExample dashed={true}
-                           height={394}
+                           height={398}
                            onContentsRendered={conversationStores[0].forcedUpdate}
                            summary="Desktop ongoing conversation window"
-                           width={298}>
+                           width={348}>
               <div className="fx-embedded">
                 <OngoingConversationView
                   audio={{ enabled: true, visible: true }}
                   chatWindowDetached={false}
                   conversationStore={conversationStores[0]}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mediaConnected={true}
@@ -1266,39 +1260,39 @@
                   mediaConnected={true}
                   remotePosterUrl="sample-img/video-screen-remote.png"
                   remoteVideoEnabled={true}
                   video={{ enabled: true, visible: true }} />
               </div>
             </FramedExample>
 
             <FramedExample dashed={true}
-                           height={394}
+                           height={398}
                            onContentsRendered={conversationStores[3].forcedUpdate}
                            summary="Desktop ongoing conversation window - local face mute"
-                           width={298}>
+                           width={348}>
               <div className="fx-embedded">
                 <OngoingConversationView
                   audio={{ enabled: true, visible: true }}
                   chatWindowDetached={false}
                   conversationStore={conversationStores[3]}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mediaConnected={true}
                   remotePosterUrl="sample-img/video-screen-remote.png"
                   remoteVideoEnabled={true}
                   video={{ enabled: false, visible: true }} />
               </div>
             </FramedExample>
 
             <FramedExample dashed={true}
-                           height={394}
+                           height={398}
                            onContentsRendered={conversationStores[4].forcedUpdate}
                            summary="Desktop ongoing conversation window - remote face mute"
-                           width={298} >
+                           width={348} >
               <div className="fx-embedded">
                 <OngoingConversationView
                   audio={{ enabled: true, visible: true }}
                   chatWindowDetached={false}
                   conversationStore={conversationStores[4]}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mediaConnected={true}
@@ -1309,31 +1303,31 @@
             </FramedExample>
 
           </Section>
 
           <Section name="FeedbackView">
             <p className="note">
             </p>
             <FramedExample dashed={true}
-                           height={272}
+                           height={288}
                            summary="Default (useable demo)"
-                           width={300}>
+                           width={348}>
               <div className="fx-embedded">
                 <FeedbackView mozLoop={{}}
                               onAfterFeedbackReceived={function() {}} />
               </div>
             </FramedExample>
           </Section>
 
           <Section name="AlertMessages">
             <FramedExample dashed={true}
-                           height={272}
+                           height={288}
                            summary="Various alerts"
-                           width={300}>
+                           width={348}>
               <div>
                 <div className="alert alert-warning">
                   <button className="close"></button>
                   <p className="message">
                     The person you were calling has ended the conversation.
                   </p>
                 </div>
                 <br />
@@ -1369,87 +1363,87 @@
                 <UnsupportedDeviceView platform="ios"/>
               </div>
             </FramedExample>
           </Section>
 
           <Section name="RoomFailureView">
             <FramedExample
               dashed={true}
-              height={254}
+              height={288}
               summary="Desktop Room Failure View"
-              width={298}>
+              width={348}>
               <div className="fx-embedded">
                 <RoomFailureView
                   dispatcher={dispatcher}
                   failureReason={FAILURE_DETAILS.UNKNOWN}
                   mozLoop={navigator.mozLoop} />
               </div>
             </FramedExample>
           </Section>
 
           <Section name="DesktopRoomConversationView">
             <FramedExample height={398}
                            onContentsRendered={invitationRoomStore.activeRoomStore.forcedUpdate}
                            summary="Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)"
-                           width={298}>
+                           width={348}>
               <div className="fx-embedded">
                 <DesktopRoomConversationView
                   chatWindowDetached={false}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mozLoop={navigator.mozLoop}
                   onCallTerminated={function(){}}
                   roomState={ROOM_STATES.INIT}
                   roomStore={invitationRoomStore} />
               </div>
             </FramedExample>
 
-            <FramedExample height={278.6}
+            <FramedExample height={288}
                            onContentsRendered={invitationRoomStore.activeRoomStore.forcedUpdate}
                            summary="Desktop room Edit Context w/Error"
-                           width={298}>
+                           width={348}>
               <div className="fx-embedded room-invitation-overlay">
                 <DesktopRoomEditContextView
                   dispatcher={dispatcher}
                   error={{}}
                   mozLoop={navigator.mozLoop}
                   onClose={function(){}}
                   roomData={{}}
                   savingContext={false}
                   show={true}
                   />
               </div>
             </FramedExample>
 
             <FramedExample dashed={true}
-                           height={394}
+                           height={398}
                            onContentsRendered={desktopRoomStoreLoading.activeRoomStore.forcedUpdate}
                            summary="Desktop room conversation (loading)"
-                           width={298}>
+                           width={348}>
               {/* Hide scrollbars here. Rotating loading div overflows and causes
                scrollbars to appear */}
               <div className="fx-embedded overflow-hidden">
                 <DesktopRoomConversationView
                   chatWindowDetached={false}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mozLoop={navigator.mozLoop}
                   onCallTerminated={function(){}}
                   remotePosterUrl="sample-img/video-screen-remote.png"
                   roomState={ROOM_STATES.HAS_PARTICIPANTS}
                   roomStore={desktopRoomStoreLoading} />
               </div>
             </FramedExample>
 
             <FramedExample dashed={true}
-                           height={394}
+                           height={398}
                            onContentsRendered={roomStore.activeRoomStore.forcedUpdate}
                            summary="Desktop room conversation"
-                           width={298}>
+                           width={348}>
               <div className="fx-embedded">
                 <DesktopRoomConversationView
                   chatWindowDetached={false}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mozLoop={navigator.mozLoop}
                   onCallTerminated={function(){}}
                   remotePosterUrl="sample-img/video-screen-remote.png"
@@ -1490,36 +1484,36 @@
                   onCallTerminated={function(){}}
                   remotePosterUrl="sample-img/video-screen-remote.png"
                   roomState={ROOM_STATES.HAS_PARTICIPANTS}
                   roomStore={desktopRoomStoreLarge} />
               </div>
             </FramedExample>
 
             <FramedExample dashed={true}
-                           height={394}
+                           height={398}
                            onContentsRendered={desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate}
                            summary="Desktop room conversation local face-mute"
-                           width={298}>
+                           width={348}>
               <div className="fx-embedded">
                 <DesktopRoomConversationView
                   chatWindowDetached={false}
                   dispatcher={dispatcher}
                   mozLoop={navigator.mozLoop}
                   onCallTerminated={function(){}}
                   remotePosterUrl="sample-img/video-screen-remote.png"
                   roomStore={desktopLocalFaceMuteRoomStore} />
               </div>
             </FramedExample>
 
             <FramedExample dashed={true}
-                           height={394}
+                           height={398}
                            onContentsRendered={desktopRemoteFaceMuteRoomStore.activeRoomStore.forcedUpdate}
                            summary="Desktop room conversation remote face-mute"
-                           width={298} >
+                           width={348} >
               <div className="fx-embedded">
                 <DesktopRoomConversationView
                   chatWindowDetached={false}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mozLoop={navigator.mozLoop}
                   onCallTerminated={function(){}}
                   remotePosterUrl="sample-img/video-screen-remote.png"
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -156,31 +156,25 @@ this.UITour = {
       allowAdd: true,
       query: "#loop-button",
       widgetName: "loop-button",
     }],
     ["loop-newRoom", {
       infoPanelPosition: "leftcenter topright",
       query: (aDocument) => {
         let loopUI = aDocument.defaultView.LoopUI;
-        if (loopUI.selectedTab != "rooms") {
-          return null;
-        }
         // Use the parentElement full-width container of the button so our arrow
         // doesn't overlap the panel contents much.
         return loopUI.browser.contentDocument.querySelector(".new-room-button").parentElement;
       },
     }],
     ["loop-roomList", {
       infoPanelPosition: "leftcenter topright",
       query: (aDocument) => {
         let loopUI = aDocument.defaultView.LoopUI;
-        if (loopUI.selectedTab != "rooms") {
-          return null;
-        }
         return loopUI.browser.contentDocument.querySelector(".room-list");
       },
     }],
     ["loop-selectedRoomButtons", {
       infoPanelOffsetY: -20,
       infoPanelPosition: "start_after",
       query: (aDocument) => {
         let chatbox = aDocument.querySelector("chatbox[src^='about\:loopconversation'][selected]");
--- a/browser/components/uitour/test/browser_UITour_loop.js
+++ b/browser/components/uitour/test/browser_UITour_loop.js
@@ -179,65 +179,16 @@ var tests = [
           yield Promise.all(hiddenPromises);
           isnot(infoPanel.state, "open", "Info panel should have automatically hid");
           isnot(highlightPanel.state, "open", "Highlight panel should have automatically hid");
           done();
         }), "Info panel should be anchored to the new room button");
       });
     });
   },
-  taskify(function* test_panelTabChangeNotifications() {
-    // First make sure the Loop panel looks like we're logged in to have more than
-    // just one tab to switch to.
-    const fxASampleToken = {
-      token_type: "bearer",
-      access_token: "1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",
-      scope: "profile"
-    };
-    const fxASampleProfile = {
-      email: "test@example.com",
-      uid: "abcd1234"
-    };
-    MozLoopServiceInternal.fxAOAuthTokenData = fxASampleToken;
-    MozLoopServiceInternal.fxAOAuthProfile = fxASampleProfile;
-    Services.prefs.setCharPref("loop.key.fxa", "fake");
-    yield MozLoopServiceInternal.notifyStatusChanged("login");
-
-    // Show the Loop menu.
-    yield showMenuPromise("loop");
-
-    // Listen for and test the notifications that will arrive from now on.
-    let tabChangePromise = new Promise(resolve => {
-      gContentAPI.observe((event, params) => {
-        is(event, "Loop:PanelTabChanged", "Check Loop:PanelTabChanged notification");
-        is(params, "contacts", "Check the tab name param");
-
-        gContentAPI.observe((event, params) => {
-          is(event, "Loop:PanelTabChanged", "Check Loop:PanelTabChanged notification");
-          is(params, "rooms", "Check the tab name param");
-
-          gContentAPI.observe((event, params) => {
-            ok(false, "No more notifications should have arrived");
-          });
-          resolve();
-        });
-      });
-    });
-
-    // Switch to the contacts tab.
-    yield window.LoopUI.openCallPanel(null, "contacts");
-
-    // Logout. The panel tab will switch back to 'rooms'.
-    MozLoopServiceInternal.fxAOAuthTokenData =
-      MozLoopServiceInternal.fxAOAuthProfile = null;
-    Services.prefs.clearUserPref("loop.key.fxa");
-    yield MozLoopServiceInternal.notifyStatusChanged();
-
-    yield tabChangePromise;
-  }),
   runOffline(function test_notifyLoopChatWindowOpenedClosed(done) {
     gContentAPI.observe((event, params) => {
       is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
       gContentAPI.observe((event, params) => {
         is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
         gContentAPI.observe((event, params) => {
           is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
           gContentAPI.observe((event, params) => {
--- a/browser/locales/en-US/chrome/browser/loop/loop.properties
+++ b/browser/locales/en-US/chrome/browser/loop/loop.properties
@@ -4,19 +4,16 @@
 
 # Panel Strings
 
 ## LOCALIZATION NOTE(clientShortname2): This should not be localized and
 ## should remain "Firefox Hello" for all locales.
 clientShortname2=Firefox Hello
 clientSuperShortname=Hello
 
-rooms_tab_button=Conversations
-contacts_tab_button=Contacts
-
 ## LOCALIZATION_NOTE(sign_in_again_title_line_one, sign_in_again_title_line_two2):
 ## These are displayed together at the top of the panel when a user is needed to
 ## sign-in again. The emphesis is on the first line to get the user to sign-in again,
 ## and this is displayed in slightly larger font. Please arrange as necessary for
 ## your locale.
 ## {{clientShortname2}} will be replaced by the brand name for either string.
 sign_in_again_title_line_one=Please sign in again
 sign_in_again_title_line_two2=to continue using {{clientShortname2}}
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -888,17 +888,17 @@ toolbarbutton[constrain-size="true"][cui
   -moz-margin-start: 0;
 }
 
 .urlbar-history-dropmarker {
   -moz-appearance: toolbarbutton-dropdown;
   transition: opacity 0.15s ease;
 }
 
-#urlbar:not(:hover) > .urlbar-textbox-container > .urlbar-history-dropmarker {
+#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 #urlbar-container {
   -moz-box-align: center;
 }
 
 @conditionalForwardWithUrlbar@ > #urlbar {
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1691,17 +1691,17 @@ toolbarbutton[constrain-size="true"][cui
 
 .urlbar-history-dropmarker {
   padding: 0 3px;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
   transition: opacity 0.15s ease;
 }
 
-#urlbar:not(:hover) > .urlbar-textbox-container > .urlbar-history-dropmarker {
+#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 .urlbar-history-dropmarker[open="true"],
 .urlbar-history-dropmarker:hover:active {
   -moz-image-region: var(--urlbar-dropmarker-active-region);
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -44,16 +44,28 @@
   --urlbar-dropmarker-hover-2x-region: rect(0, 44px, 28px, 22px);
   --urlbar-dropmarker-active-2x-region: rect(0, 66px, 28px, 44px);
 
   --panel-separator-color: ThreeDLightShadow;
 
   --urlbar-separator-color: hsla(0,0%,16%,.2);
 }
 
+#nav-bar[brighttext] {
+  --toolbarbutton-hover-background: rgba(255,255,255,.25);
+  --toolbarbutton-hover-bordercolor: rgba(255,255,255,.5);
+  --toolbarbutton-hover-boxshadow: none;
+
+  --toolbarbutton-active-background: rgba(255,255,255,.4);
+  --toolbarbutton-active-bordercolor: rgba(255,255,255,.7);
+  --toolbarbutton-active-boxshadow: 0 0 0 1px rgba(255,255,255,.4) inset;
+
+  --toolbarbutton-checkedhover-backgroundcolor: rgba(255,255,255,.3);
+}
+
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
 }
 
@@ -1113,16 +1125,20 @@ toolbarbutton[constrain-size="true"][cui
   --urlbar-border-color: ThreeDShadow;
   --urlbar-border-color-hover: var(--urlbar-border-color);
 }
 
 #nav-bar:-moz-lwtheme {
   --urlbar-border-color: rgba(0,0,0,.32);
 }
 
+#nav-bar:-moz-lwtheme-brighttext {
+  --urlbar-border-color: var(--toolbarbutton-hover-bordercolor);
+}
+
 @media (-moz-windows-default-theme) {
   @media (-moz-os-version: windows-vista),
          (-moz-os-version: windows-win7),
          (-moz-os-version: windows-win8) {
     #nav-bar:not(:-moz-lwtheme) {
       --urlbar-border-color: hsla(210,54%,20%,.25) hsla(210,54%,20%,.27) hsla(210,54%,20%,.3);
       --urlbar-border-color-hover: hsla(210,54%,20%,.35) hsla(210,54%,20%,.37) hsla(210,54%,20%,.4);
     }
@@ -1141,16 +1157,21 @@ toolbarbutton[constrain-size="true"][cui
   -moz-appearance: none;
   margin: 0 3px;
   padding: 0;
   background-clip: padding-box;
   border: 1px solid;
   border-color: var(--urlbar-border-color);
 }
 
+#urlbar:-moz-lwtheme-brighttext,
+.searchbar-textbox:-moz-lwtheme-brighttext {
+  background-clip: border-box;
+}
+
 #urlbar:hover,
 .searchbar-textbox:hover {
   border-color: var(--urlbar-border-color-hover);
 }
 
 /* overlap the urlbar's border */
 #PopupAutoCompleteRichResult {
   margin-top: -1px;
@@ -1371,17 +1392,17 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
   background-color: transparent;
   border: none;
   width: auto;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
   transition: opacity 0.15s ease;
 }
 
-#urlbar:not(:hover) > .urlbar-textbox-container > .urlbar-history-dropmarker {
+#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 .urlbar-history-dropmarker:hover {
   -moz-image-region: var(--urlbar-dropmarker-hover-region);
 }
 
 .urlbar-history-dropmarker:hover:active,
--- a/devtools/client/debugger/debugger-controller.js
+++ b/devtools/client/debugger/debugger-controller.js
@@ -37,16 +37,17 @@ const EVENTS = {
   FETCHED_VARIABLES: "Debugger:FetchedVariables",
   FETCHED_PROPERTIES: "Debugger:FetchedProperties",
   FETCHED_BUBBLE_PROPERTIES: "Debugger:FetchedBubbleProperties",
   FETCHED_WATCH_EXPRESSIONS: "Debugger:FetchedWatchExpressions",
 
   // When a breakpoint has been added or removed on the debugger server.
   BREAKPOINT_ADDED: "Debugger:BreakpointAdded",
   BREAKPOINT_REMOVED: "Debugger:BreakpointRemoved",
+  BREAKPOINT_CLICKED: "Debugger:BreakpointClicked",
 
   // When a breakpoint has been shown or hidden in the source editor
   // or the pane.
   BREAKPOINT_SHOWN_IN_EDITOR: "Debugger:BreakpointShownInEditor",
   BREAKPOINT_SHOWN_IN_PANE: "Debugger:BreakpointShownInPane",
   BREAKPOINT_HIDDEN_IN_EDITOR: "Debugger:BreakpointHiddenInEditor",
   BREAKPOINT_HIDDEN_IN_PANE: "Debugger:BreakpointHiddenInPane",
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-02.js
@@ -190,13 +190,15 @@ function test() {
       "The editor caret position is not properly set.");
   }
 
   function setCaretPosition(aLine) {
     gEditor.setCursor({ line: aLine - 1, ch: 0 });
   }
 
   function clickOnBreakpoint(aIndex) {
+    let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.BREAKPOINT_CLICKED);
     EventUtils.sendMouseEvent({ type: "click" },
       gDebugger.document.querySelectorAll(".dbg-breakpoint")[aIndex],
       gDebugger);
+    return finished;
   }
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-02.js
@@ -179,13 +179,15 @@ function test() {
       "The editor caret position is not properly set.");
   }
 
   function setCaretPosition(aLine) {
     gEditor.setCursor({ line: aLine - 1, ch: 0 });
   }
 
   function clickOnBreakpoint(aIndex) {
+    let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.BREAKPOINT_CLICKED);
     EventUtils.sendMouseEvent({ type: "click" },
       gDebugger.document.querySelectorAll(".dbg-breakpoint")[aIndex],
       gDebugger);
+    return finished;
   }
 }
--- a/devtools/client/debugger/views/sources-view.js
+++ b/devtools/client/debugger/views/sources-view.js
@@ -461,19 +461,19 @@ SourcesView.prototype = Heritage.extend(
     // Update the editor location if necessary.
     if (!aOptions.noEditorUpdate) {
       this.DebuggerView.setEditorLocation(aLocation.actor, aLocation.line, { noDebug: true });
     }
 
     // If the breakpoint requires a new conditional expression, display
     // the panel to input the corresponding expression.
     if (aOptions.openPopup) {
-      this._openConditionalPopup();
+      return this._openConditionalPopup();
     } else {
-      this._hideConditionalPopup();
+      return this._hideConditionalPopup();
     }
   },
 
   /**
    * Highlight the breakpoint on the current currently focused line/column
    * if it exists.
    */
   highlightBreakpointAtCursor: function() {
@@ -712,23 +712,23 @@ SourcesView.prototype = Heritage.extend(
    */
   _openConditionalPopup: function() {
     let breakpointItem = this._selectedBreakpointItem;
     let attachment = breakpointItem.attachment;
     // Check if this is an enabled conditional breakpoint, and if so,
     // retrieve the current conditional epression.
     let breakpointPromise = this.Breakpoints._getAdded(attachment);
     if (breakpointPromise) {
-      breakpointPromise.then(aBreakpointClient => {
+      return breakpointPromise.then(aBreakpointClient => {
         let isConditionalBreakpoint = aBreakpointClient.hasCondition();
         let condition = aBreakpointClient.getCondition();
-        doOpen.call(this, isConditionalBreakpoint ? condition : "")
+        return doOpen.call(this, isConditionalBreakpoint ? condition : "")
       });
     } else {
-      doOpen.call(this, "")
+      return doOpen.call(this, "")
     }
 
     function doOpen(aConditionalExpression) {
       // Update the conditional expression textbox. If no expression was
       // previously set, revert to using an empty string by default.
       this._cbTextbox.value = aConditionalExpression;
 
       // Show the conditional expression panel. The popup arrow should be pointing
@@ -1035,28 +1035,34 @@ SourcesView.prototype = Heritage.extend(
    * The click listener for a breakpoint container.
    */
   _onBreakpointClick: function(e) {
     let sourceItem = this.getItemForElement(e.target);
     let breakpointItem = this.getItemForElement.call(sourceItem, e.target);
     let attachment = breakpointItem.attachment;
 
     // Check if this is an enabled conditional breakpoint.
-    let breakpointPromise = this.Breakpoints._getAdded(attachment);
-    if (breakpointPromise) {
-      breakpointPromise.then(aBreakpointClient => {
-        doHighlight.call(this, aBreakpointClient.hasCondition());
+    let promise = this.Breakpoints._getAdded(attachment);
+    if (promise) {
+      promise = promise.then(aBreakpointClient => {
+        return doHighlight.call(this, aBreakpointClient.hasCondition());
       });
     } else {
-      doHighlight.call(this, false);
+      promise = Promise.resolve().then(() => {
+        return doHighlight.call(this, false)
+      });
     }
 
+    promise.then(() => {
+      window.emit(EVENTS.BREAKPOINT_CLICKED);
+    });
+
     function doHighlight(aConditionalBreakpointFlag) {
       // Highlight the breakpoint in this pane and in the editor.
-      this.highlightBreakpoint(attachment, {
+      return this.highlightBreakpoint(attachment, {
         // Don't show the conditional expression popup if this is not a
         // conditional breakpoint, or the right mouse button was pressed (to
         // avoid clashing the popup with the context menu).
         openPopup: aConditionalBreakpointFlag && e.button == 0
       });
     }
   },
 
--- a/devtools/client/framework/gDevTools.jsm
+++ b/devtools/client/framework/gDevTools.jsm
@@ -546,24 +546,16 @@ var gDevToolsBrowser = {
 
     // If a toolbox exists, using toggle from the Main window :
     // - should close a docked toolbox
     // - should focus a windowed toolbox
     let isDocked = toolbox && toolbox.hostType != Toolbox.HostType.WINDOW;
     isDocked ? toolbox.destroy() : gDevTools.showToolbox(target);
   },
 
-  toggleBrowserToolboxCommand: function(gBrowser) {
-    let target = TargetFactory.forWindow(gBrowser.ownerDocument.defaultView);
-    let toolbox = gDevTools.getToolbox(target);
-
-    toolbox ? toolbox.destroy()
-     : gDevTools.showToolbox(target, "inspector", Toolbox.HostType.WINDOW);
-  },
-
   /**
    * This function ensures the right commands are enabled in a window,
    * depending on their relevant prefs. It gets run when a window is registered,
    * or when any of the devtools prefs change.
    */
   updateCommandAvailability: function(win) {
     let doc = win.document;
 
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -1,37 +1,38 @@
 /* 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";
 
-const {Cc, Ci, Cu} = require("chrome");
+const { Ci, Cu } = require("chrome");
 const promise = require("promise");
 const EventEmitter = require("devtools/shared/event-emitter");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
-loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "DebuggerClient",
+  "devtools/shared/client/main", true);
 
 const targets = new WeakMap();
 const promiseTargets = new WeakMap();
 
 /**
  * Functions for creating Targets
  */
 exports.TargetFactory = {
   /**
    * Construct a Target
    * @param {XULTab} tab
    *        The tab to use in creating a new target.
    *
    * @return A target object
    */
-  forTab: function TF_forTab(tab) {
+  forTab: function(tab) {
     let target = targets.get(tab);
     if (target == null) {
       target = new TabTarget(tab);
       targets.set(tab, target);
     }
     return target;
   },
 
@@ -43,129 +44,76 @@ exports.TargetFactory = {
    *          form: the remote protocol form of a tab,
    *          client: a DebuggerClient instance
    *                  (caller owns this and is responsible for closing),
    *          chrome: true if the remote target is the whole process
    *        }
    *
    * @return A promise of a target object
    */
-  forRemoteTab: function TF_forRemoteTab(options) {
+  forRemoteTab: function(options) {
     let targetPromise = promiseTargets.get(options);
     if (targetPromise == null) {
       let target = new TabTarget(options);
       targetPromise = target.makeRemote().then(() => target);
       promiseTargets.set(options, targetPromise);
     }
     return targetPromise;
   },
 
-  forWorker: function TF_forWorker(workerClient) {
+  forWorker: function(workerClient) {
     let target = targets.get(workerClient);
     if (target == null) {
       target = new WorkerTarget(workerClient);
       targets.set(workerClient, target);
     }
     return target;
   },
 
   /**
    * Creating a target for a tab that is being closed is a problem because it
    * allows a leak as a result of coming after the close event which normally
    * clears things up. This function allows us to ask if there is a known
    * target for a tab without creating a target
    * @return true/false
    */
-  isKnownTab: function TF_isKnownTab(tab) {
+  isKnownTab: function(tab) {
     return targets.has(tab);
   },
-
-  /**
-   * Construct a Target
-   * @param {nsIDOMWindow} window
-   *        The chromeWindow to use in creating a new target
-   * @return A target object
-   */
-  forWindow: function TF_forWindow(window) {
-    let target = targets.get(window);
-    if (target == null) {
-      target = new WindowTarget(window);
-      targets.set(window, target);
-    }
-    return target;
-  },
-
-  /**
-   * Get all of the targets known to the local browser instance
-   * @return An array of target objects
-   */
-  allTargets: function TF_allTargets() {
-    let windows = [];
-    let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
-                       .getService(Ci.nsIWindowMediator);
-    let en = wm.getXULWindowEnumerator(null);
-    while (en.hasMoreElements()) {
-      windows.push(en.getNext());
-    }
-
-    return windows.map(function(window) {
-      return TargetFactory.forWindow(window);
-    });
-  },
 };
 
 /**
- * The 'version' property allows the developer tools equivalent of browser
- * detection. Browser detection is evil, however while we don't know what we
- * will need to detect in the future, it is an easy way to postpone work.
- * We should be looking to use the support features added in bug 1069673
- * in place of version where possible.
- */
-function getVersion() {
-  // FIXME: return something better
-  return 20;
-}
-
-/**
  * A Target represents something that we can debug. Targets are generally
  * read-only. Any changes that you wish to make to a target should be done via
  * a Tool that attaches to the target. i.e. a Target is just a pointer saying
  * "the thing to debug is over there".
  *
  * Providing a generalized abstraction of a web-page or web-browser (available
  * either locally or remotely) is beyond the scope of this class (and maybe
  * also beyond the scope of this universe) However Target does attempt to
  * abstract some common events and read-only properties common to many Tools.
  *
  * Supported read-only properties:
  * - name, isRemote, url
  *
  * Target extends EventEmitter and provides support for the following events:
  * - close: The target window has been closed. All tools attached to this
- *     target should close. This event is not currently cancelable.
+ *          target should close. This event is not currently cancelable.
  * - navigate: The target window has navigated to a different URL
  *
  * Optional events:
  * - will-navigate: The target window will navigate to a different URL
- * - hidden: The target is not visible anymore (for TargetTab, another tab is selected)
+ * - hidden: The target is not visible anymore (for TargetTab, another tab is
+ *           selected)
  * - visible: The target is visible (for TargetTab, tab is selected)
  *
  * Comparing Targets: 2 instances of a Target object can point at the same
  * thing, so t1 !== t2 and t1 != t2 even when they represent the same object.
  * To compare to targets use 't1.equals(t2)'.
  */
-function Target() {
-  throw new Error("Use TargetFactory.newXXX or Target.getXXX to create a Target in place of 'new Target()'");
-}
-
-Object.defineProperty(Target.prototype, "version", {
-  get: getVersion,
-  enumerable: true
-});
-
 
 /**
  * A TabTarget represents a page living in a browser tab. Generally these will
  * be web pages served over http(s), but they don't have to be.
  */
 function TabTarget(tab) {
   EventEmitter.decorate(this);
   this.destroy = this.destroy.bind(this);
@@ -178,32 +126,36 @@ function TabTarget(tab) {
   if (tab && !["client", "form", "chrome"].every(tab.hasOwnProperty, tab)) {
     this._tab = tab;
     this._setupListeners();
   } else {
     this._form = tab.form;
     this._client = tab.client;
     this._chrome = tab.chrome;
   }
-  // Default isTabActor to true if not explicitely specified
-  this._isTabActor = typeof(tab.isTabActor) == "boolean" ? tab.isTabActor : true;
+  // Default isTabActor to true if not explicitly specified
+  if (typeof tab.isTabActor == "boolean") {
+    this._isTabActor = tab.isTabActor;
+  } else {
+    this._isTabActor = true;
+  }
 }
 
 TabTarget.prototype = {
   _webProgressListener: null,
 
   /**
-   * Returns a promise for the protocol description from the root actor.
-   * Used internally with `target.actorHasMethod`. Takes advantage of
-   * caching if definition was fetched previously with the corresponding
-   * actor information. Actors are lazily loaded, so not only must the tool using
-   * a specific actor be in use, the actors are only registered after invoking
-   * a method (for performance reasons, added in bug 988237), so to use these actor
-   * detection methods, one must already be communicating with a specific actor of
-   * that type.
+   * Returns a promise for the protocol description from the root actor. Used
+   * internally with `target.actorHasMethod`. Takes advantage of caching if
+   * definition was fetched previously with the corresponding actor information.
+   * Actors are lazily loaded, so not only must the tool using a specific actor
+   * be in use, the actors are only registered after invoking a method (for
+   * performance reasons, added in bug 988237), so to use these actor detection
+   * methods, one must already be communicating with a specific actor of that
+   * type.
    *
    * Must be a remote target.
    *
    * @return {Promise}
    * {
    *   "category": "actor",
    *   "typeName": "longstractor",
    *   "methods": [{
@@ -223,24 +175,26 @@ TabTarget.prototype = {
    *       "substring": {
    *         "_retval": "primitive"
    *       }
    *     }
    *   }],
    *  "events": {}
    * }
    */
-  getActorDescription: function (actorName) {
+  getActorDescription: function(actorName) {
     if (!this.client) {
-      throw new Error("TabTarget#getActorDescription() can only be called on remote tabs.");
+      throw new Error("TabTarget#getActorDescription() can only be called on " +
+                      "remote tabs.");
     }
 
     let deferred = promise.defer();
 
-    if (this._protocolDescription && this._protocolDescription.types[actorName]) {
+    if (this._protocolDescription &&
+        this._protocolDescription.types[actorName]) {
       deferred.resolve(this._protocolDescription.types[actorName]);
     } else {
       this.client.mainRoot.protocolDescription(description => {
         this._protocolDescription = description;
         deferred.resolve(description.types[actorName]);
       });
     }
 
@@ -249,19 +203,20 @@ TabTarget.prototype = {
 
   /**
    * Returns a boolean indicating whether or not the specific actor
    * type exists. Must be a remote target.
    *
    * @param {String} actorName
    * @return {Boolean}
    */
-  hasActor: function (actorName) {
+  hasActor: function(actorName) {
     if (!this.client) {
-      throw new Error("TabTarget#hasActor() can only be called on remote tabs.");
+      throw new Error("TabTarget#hasActor() can only be called on remote " +
+                      "tabs.");
     }
     if (this.form) {
       return !!this.form[actorName + "Actor"];
     }
     return false;
   },
 
   /**
@@ -270,50 +225,50 @@ TabTarget.prototype = {
    * the restrictions in the `getActorDescription` comments),
    * so this is for use inside of tool. Returns a promise that
    * resolves to a boolean. Must be a remote target.
    *
    * @param {String} actorName
    * @param {String} methodName
    * @return {Promise}
    */
-  actorHasMethod: function (actorName, methodName) {
+  actorHasMethod: function(actorName, methodName) {
     if (!this.client) {
-      throw new Error("TabTarget#actorHasMethod() can only be called on remote tabs.");
+      throw new Error("TabTarget#actorHasMethod() can only be called on " +
+                      "remote tabs.");
     }
     return this.getActorDescription(actorName).then(desc => {
       if (desc && desc.methods) {
         return !!desc.methods.find(method => method.name === methodName);
       }
       return false;
     });
   },
 
   /**
    * Returns a trait from the root actor.
    *
    * @param {String} traitName
    * @return {Mixed}
    */
-  getTrait: function (traitName) {
+  getTrait: function(traitName) {
     if (!this.client) {
-      throw new Error("TabTarget#getTrait() can only be called on remote tabs.");
+      throw new Error("TabTarget#getTrait() can only be called on remote " +
+                      "tabs.");
     }
 
-    // If the targeted actor exposes traits and has a defined value for this traits,
-    // override the root actor traits
+    // If the targeted actor exposes traits and has a defined value for this
+    // traits, override the root actor traits
     if (this.form.traits && traitName in this.form.traits) {
       return this.form.traits[traitName];
     }
 
     return this.client.traits[traitName];
   },
 
-  get version() { return getVersion(); },
-
   get tab() {
     return this._tab;
   },
 
   get form() {
     return this._form;
   },
 
@@ -321,17 +276,17 @@ TabTarget.prototype = {
   // is cached.
   get root() {
     if (!this._root) {
       this._root = this._getRoot();
     }
     return this._root;
   },
 
-  _getRoot: function () {
+  _getRoot: function() {
     return new Promise((resolve, reject) => {
       this.client.listTabs(response => {
         if (response.error) {
           reject(new Error(response.error + ": " + response.message));
           return;
         }
 
         resolve(response);
@@ -359,35 +314,35 @@ TabTarget.prototype = {
   },
 
   get window() {
     // XXX - this is a footgun for e10s - there .contentWindow will be null,
     // and even though .contentWindowAsCPOW *might* work, it will not work
     // in all contexts.  Consumers of .window need to be refactored to not
     // rely on this.
     if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
-      Cu.reportError("The .window getter on devtools' |target| object isn't e10s friendly!\n"
-                     + Error().stack);
+      Cu.reportError("The .window getter on devtools' |target| object isn't " +
+                     "e10s friendly!\n" + Error().stack);
     }
     // Be extra careful here, since this may be called by HS_getHudByWindow
     // during shutdown.
     if (this._tab && this._tab.linkedBrowser) {
       return this._tab.linkedBrowser.contentWindow;
     }
     return null;
   },
 
   get name() {
     if (this._tab && this._tab.linkedBrowser.contentDocument) {
-      return this._tab.linkedBrowser.contentDocument.title
-    } else if (this.isAddon) {
+      return this._tab.linkedBrowser.contentDocument.title;
+    }
+    if (this.isAddon) {
       return this._form.name;
-    } else {
-      return this._form.title;
     }
+    return this._form.title;
   },
 
   get url() {
     return this._tab ? this._tab.linkedBrowser.currentURI.spec :
                        this._form.url;
   },
 
   get isRemote() {
@@ -411,17 +366,17 @@ TabTarget.prototype = {
     return !!this._isThreadPaused;
   },
 
   /**
    * Adds remote protocol capabilities to the target, so that it can be used
    * for tools that support the Remote Debugging Protocol even for local
    * connections.
    */
-  makeRemote: function TabTarget_makeRemote() {
+  makeRemote: function() {
     if (this._remote) {
       return this._remote.promise;
     }
 
     this._remote = promise.defer();
 
     if (this.isLocalTab) {
       // Since a remote protocol connection will be made, let's start the
@@ -434,89 +389,90 @@ TabTarget.prototype = {
       this._client = new DebuggerClient(DebuggerServer.connectPipe());
       // A local TabTarget will never perform chrome debugging.
       this._chrome = false;
     }
 
     this._setupRemoteListeners();
 
     let attachTab = () => {
-      this._client.attachTab(this._form.actor, (aResponse, aTabClient) => {
-        if (!aTabClient) {
+      this._client.attachTab(this._form.actor, (response, tabClient) => {
+        if (!tabClient) {
           this._remote.reject("Unable to attach to the tab");
           return;
         }
-        this.activeTab = aTabClient;
-        this.threadActor = aResponse.threadActor;
+        this.activeTab = tabClient;
+        this.threadActor = response.threadActor;
         attachConsole();
       });
     };
 
+    let onConsoleAttached = (response, consoleClient) => {
+      if (!consoleClient) {
+        this._remote.reject("Unable to attach to the console");
+        return;
+      }
+      this.activeConsole = consoleClient;
+      this._remote.resolve(null);
+    };
+
     let attachConsole = () => {
       this._client.attachConsole(this._form.consoleActor,
                                  [ "NetworkActivity" ],
-                                 (aResponse, aWebConsoleClient) => {
-        if (!aWebConsoleClient) {
-          this._remote.reject("Unable to attach to the console");
-          return;
-        }
-        this.activeConsole = aWebConsoleClient;
-        this._remote.resolve(null);
-      });
+                                 onConsoleAttached);
     };
 
     if (this.isLocalTab) {
-      this._client.connect((aType, aTraits) => {
-        this._client.getTab({ tab: this.tab })
-            .then(aResponse => {
-          this._form = aResponse.tab;
+      this._client.connect(() => {
+        this._client.getTab({ tab: this.tab }).then(response => {
+          this._form = response.tab;
           attachTab();
         });
       });
     } else if (this.isTabActor) {
       // In the remote debugging case, the protocol connection will have been
       // already initialized in the connection screen code.
       attachTab();
     } else {
-      // AddonActor and chrome debugging on RootActor doesn't inherits from TabActor and
-      // doesn't need to be attached.
+      // AddonActor and chrome debugging on RootActor doesn't inherits from
+      // TabActor and doesn't need to be attached.
       attachConsole();
     }
 
     return this._remote.promise;
   },
 
   /**
    * Listen to the different events.
    */
-  _setupListeners: function TabTarget__setupListeners() {
+  _setupListeners: function() {
     this._webProgressListener = new TabWebProgressListener(this);
     this.tab.linkedBrowser.addProgressListener(this._webProgressListener);
     this.tab.addEventListener("TabClose", this);
     this.tab.parentNode.addEventListener("TabSelect", this);
     this.tab.ownerDocument.defaultView.addEventListener("unload", this);
   },
 
   /**
    * Teardown event listeners.
    */
-  _teardownListeners: function TabTarget__teardownListeners() {
+  _teardownListeners: function() {
     if (this._webProgressListener) {
       this._webProgressListener.destroy();
     }
 
     this._tab.ownerDocument.defaultView.removeEventListener("unload", this);
     this._tab.removeEventListener("TabClose", this);
     this._tab.parentNode.removeEventListener("TabSelect", this);
   },
 
   /**
    * Setup listeners for remote debugging, updating existing ones as necessary.
    */
-  _setupRemoteListeners: function TabTarget__setupRemoteListeners() {
+  _setupRemoteListeners: function() {
     this.client.addListener("closed", this.destroy);
 
     this._onTabDetached = (aType, aPacket) => {
       // We have to filter message to ensure that this detach is for this tab
       if (aPacket.from == this._form.actor) {
         this.destroy();
       }
     };
@@ -546,27 +502,27 @@ TabTarget.prototype = {
       this.emit("frame-update", aPacket);
     };
     this.client.addListener("frameUpdate", this._onFrameUpdate);
   },
 
   /**
    * Teardown listeners for remote debugging.
    */
-  _teardownRemoteListeners: function TabTarget__teardownRemoteListeners() {
+  _teardownRemoteListeners: function() {
     this.client.removeListener("closed", this.destroy);
     this.client.removeListener("tabNavigated", this._onTabNavigated);
     this.client.removeListener("tabDetached", this._onTabDetached);
     this.client.removeListener("frameUpdate", this._onFrameUpdate);
   },
 
   /**
    * Handle tabs events.
    */
-  handleEvent: function (event) {
+  handleEvent: function(event) {
     switch (event.type) {
       case "TabClose":
       case "unload":
         this.destroy();
         break;
       case "TabSelect":
         if (this.tab.selected) {
           this.emit("visible", event);
@@ -645,52 +601,53 @@ TabTarget.prototype = {
     }
 
     return this._destroyer.promise;
   },
 
   /**
    * Clean up references to what this target points to.
    */
-  _cleanup: function TabTarget__cleanup() {
+  _cleanup: function() {
     if (this._tab) {
       targets.delete(this._tab);
     } else {
       promiseTargets.delete(this._form);
     }
     this.activeTab = null;
     this.activeConsole = null;
     this._client = null;
     this._tab = null;
     this._form = null;
     this._remote = null;
   },
 
   toString: function() {
-    return 'TabTarget:' + (this._tab ? this._tab : (this._form && this._form.actor));
+    let id = this._tab ? this._tab : (this._form && this._form.actor);
+    return `TabTarget:${id}`;
   },
 };
 
-
 /**
  * WebProgressListener for TabTarget.
  *
  * @param object aTarget
  *        The TabTarget instance to work with.
  */
 function TabWebProgressListener(aTarget) {
   this.target = aTarget;
 }
 
 TabWebProgressListener.prototype = {
   target: null,
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                         Ci.nsISupportsWeakReference]),
 
-  onStateChange: function TWPL_onStateChange(progress, request, flag, status) {
+  onStateChange: function(progress, request, flag) {
     let isStart = flag & Ci.nsIWebProgressListener.STATE_START;
     let isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
     let isNetwork = flag & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
     let isRequest = flag & Ci.nsIWebProgressListener.STATE_IS_REQUEST;
 
     // Skip non-interesting states.
     if (!isStart || !isDocument || !isRequest || !isNetwork) {
       return;
@@ -707,129 +664,48 @@ TabWebProgressListener.prototype = {
       }
     }
   },
 
   onProgressChange: function() {},
   onSecurityChange: function() {},
   onStatusChange: function() {},
 
-  onLocationChange: function TWPL_onLocationChange(webProgress, request, URI, flags) {
+  onLocationChange: function(webProgress, request, URI, flags) {
     if (this.target &&
         !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) {
       let window = webProgress.DOMWindow;
       // Emit the event if the target is not remoted or store the payload for
       // later emission otherwise.
       if (this.target._client) {
         this.target._navWindow = window;
       } else {
         this.target.emit("navigate", window);
       }
     }
   },
 
   /**
    * Destroy the progress listener instance.
    */
-  destroy: function TWPL_destroy() {
+  destroy: function() {
     if (this.target.tab) {
       try {
         this.target.tab.linkedBrowser.removeProgressListener(this);
       } catch (ex) {
         // This can throw when a tab crashes in e10s.
       }
     }
     this.target._webProgressListener = null;
     this.target._navRequest = null;
     this.target._navWindow = null;
     this.target = null;
   }
 };
 
-
-/**
- * A WindowTarget represents a page living in a xul window or panel. Generally
- * these will have a chrome: URL
- */
-function WindowTarget(window) {
-  EventEmitter.decorate(this);
-  this._window = window;
-  this._setupListeners();
-}
-
-WindowTarget.prototype = {
-  get version() { return getVersion(); },
-
-  get window() {
-    return this._window;
-  },
-
-  get name() {
-    return this._window.document.title;
-  },
-
-  get url() {
-    return this._window.document.location.href;
-  },
-
-  get isRemote() {
-    return false;
-  },
-
-  get isLocalTab() {
-    return false;
-  },
-
-  get isThreadPaused() {
-    return !!this._isThreadPaused;
-  },
-
-  /**
-   * Listen to the different events.
-   */
-  _setupListeners: function() {
-    this._handleThreadState = this._handleThreadState.bind(this);
-    this.on("thread-paused", this._handleThreadState);
-    this.on("thread-resumed", this._handleThreadState);
-  },
-
-  _handleThreadState: function(event) {
-    switch (event) {
-      case "thread-resumed":
-        this._isThreadPaused = false;
-        break;
-      case "thread-paused":
-        this._isThreadPaused = true;
-        break;
-    }
-  },
-
-  /**
-   * Target is not alive anymore.
-   */
-  destroy: function() {
-    if (!this._destroyed) {
-      this._destroyed = true;
-
-      this.off("thread-paused", this._handleThreadState);
-      this.off("thread-resumed", this._handleThreadState);
-      this.emit("close");
-
-      targets.delete(this._window);
-      this._window = null;
-    }
-
-    return promise.resolve(null);
-  },
-
-  toString: function() {
-    return 'WindowTarget:' + this.window;
-  },
-};
-
 function WorkerTarget(workerClient) {
   EventEmitter.decorate(this);
   this._workerClient = workerClient;
 }
 
 /**
  * A WorkerTarget represents a worker. Unlike TabTarget, which can represent
  * either a local or remote tab, WorkerTarget always represents a remote worker.
@@ -872,20 +748,20 @@ WorkerTarget.prototype = {
   get activeTab() {
     return this._workerClient;
   },
 
   get client() {
     return this._workerClient.client;
   },
 
-  destroy: function () {},
+  destroy: function() {},
 
-  hasActor: function (name) {
+  hasActor: function() {
     return false;
   },
 
-  getTrait: function (name) {
+  getTrait: function() {
     return undefined;
   },
 
-  makeRemote: function () {}
+  makeRemote: function() {}
 };
--- a/devtools/shared/gcli/commands/screenshot.js
+++ b/devtools/shared/gcli/commands/screenshot.js
@@ -62,21 +62,21 @@ const standardParams = {
     {
       name: "delay",
       type: { name: "number", min: 0 },
       defaultValue: 0,
       description: l10n.lookup("screenshotDelayDesc"),
       manual: l10n.lookup("screenshotDelayManual")
     },
     {
-      name: "dpi",
+      name: "dpr",
       type: { name: "number", min: 0, allowFloat: true },
       defaultValue: 0,
-      description: l10n.lookup("screenshotDPIDesc"),
-      manual: l10n.lookup("screenshotDPIManual")
+      description: l10n.lookup("screenshotDPRDesc"),
+      manual: l10n.lookup("screenshotDPRManual")
     },
     {
       name: "fullpage",
       type: "boolean",
       description: l10n.lookup("screenshotFullPageDesc"),
       manual: l10n.lookup("screenshotFullPageManual")
     },
     {
@@ -288,17 +288,17 @@ function createScreenshotData(document, 
   const scrollbarHeight = {};
   const scrollbarWidth = {};
   winUtils.getScrollbarSize(false, scrollbarWidth, scrollbarHeight);
   width -= scrollbarWidth.value;
   height -= scrollbarHeight.value;
 
   const canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
   const ctx = canvas.getContext("2d");
-  const ratio = args.dpi ? args.dpi : window.devicePixelRatio;
+  const ratio = args.dpr ? args.dpr : window.devicePixelRatio;
   canvas.width = width * ratio;
   canvas.height = height * ratio;
   ctx.scale(ratio, ratio);
   ctx.drawWindow(window, left, top, width, height, "#fff");
   const data = canvas.toDataURL("image/png", "");
 
   // See comment above on bug 961832
   if (args.fullpage) {
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -384,19 +384,18 @@ bool MediaOmxReader::DecodeVideoFrame(bo
       // and we will preserve the ratio of the crop rectangle as it
       // was reported relative to the picture size reported by the container.
       picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width;
       picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height;
       picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width;
       picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height;
     }
 
-    MOZ_ASSERT(mStreamSource);
     // This is the approximate byte position in the stream.
-    int64_t pos = mStreamSource->Tell();
+    int64_t pos = mStreamSource ? mStreamSource->Tell() : 0;
 
     nsRefPtr<VideoData> v;
     if (!frame.mGraphicBuffer) {
 
       VideoData::YCbCrBuffer b;
       b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData);
       b.mPlanes[0].mStride = frame.Y.mStride;
       b.mPlanes[0].mHeight = frame.Y.mHeight;
@@ -487,19 +486,18 @@ void MediaOmxReader::NotifyDataArrivedIn
   }
 }
 
 bool MediaOmxReader::DecodeAudioData()
 {
   MOZ_ASSERT(OnTaskQueue());
   EnsureActive();
 
-  MOZ_ASSERT(mStreamSource);
   // This is the approximate byte position in the stream.
-  int64_t pos = mStreamSource->Tell();
+  int64_t pos = mStreamSource ? mStreamSource->Tell() : 0;
 
   // Read next frame
   MPAPI::AudioFrame source;
   if (!mOmxDecoder->ReadAudio(&source, mAudioSeekTimeUs)) {
     return false;
   }
   mAudioSeekTimeUs = -1;
 
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -84,17 +84,17 @@ protected:
   static void TrimLessFitCandidates(CapabilitySet& set);
   static void LogConstraints(const dom::MediaTrackConstraintSet& aConstraints,
                              bool aAdvanced);
 static void LogCapability(const char* aHeader,
                           const webrtc::CaptureCapability &aCapability,
                           uint32_t aDistance);
   virtual size_t NumCapabilities();
   virtual void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut);
-  bool ChooseCapability(const dom::MediaTrackConstraints &aConstraints,
+  virtual bool ChooseCapability(const dom::MediaTrackConstraints &aConstraints,
                         const MediaEnginePrefs &aPrefs,
                         const nsString& aDeviceId);
   void SetName(nsString aName);
   void SetUUID(const char* aUUID);
   const nsCString& GetUUID(); // protected access
 
   // Engine variables.
 
@@ -113,17 +113,17 @@ static void LogCapability(const char* aH
   // end of data protected by mMonitor
 
 
   bool mInitDone;
   bool mHasDirectListeners;
   int mCaptureIndex;
   TrackID mTrackID;
 
-  webrtc::CaptureCapability mCapability; // Doesn't work on OS X.
+  webrtc::CaptureCapability mCapability;
 
   nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities; // For OSX & B2G
 private:
   nsString mDeviceName;
   nsCString mUniqueId;
   nsString mFacingMode;
 };
 
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -382,16 +382,41 @@ MediaEngineRemoteVideoSource::NumCapabil
     c.maxFPS = 0;
     mHardcodedCapabilities.AppendElement(c);
     break;
   }
 
   return mHardcodedCapabilities.Length();
 }
 
+bool
+MediaEngineRemoteVideoSource::ChooseCapability(const MediaTrackConstraints &aConstraints,
+    const MediaEnginePrefs &aPrefs,
+    const nsString& aDeviceId)
+{
+
+  switch(mMediaSource) {
+    case dom::MediaSourceEnum::Screen:
+    case dom::MediaSourceEnum::Window:
+    case dom::MediaSourceEnum::Application: {
+      FlattenedConstraints c(aConstraints);
+      mCapability.width = c.mWidth.Clamp(c.mWidth.mIdeal.WasPassed() ?
+        c.mWidth.mIdeal.Value() : aPrefs.mWidth);
+      mCapability.height = c.mHeight.Clamp(c.mHeight.mIdeal.WasPassed() ?
+        c.mHeight.mIdeal.Value() : aPrefs.mHeight);
+      mCapability.maxFPS = c.mFrameRate.Clamp(c.mFrameRate.mIdeal.WasPassed() ?
+        c.mFrameRate.mIdeal.Value() : aPrefs.mFPS);
+      return true;
+    }
+    default:
+      return MediaEngineCameraVideoSource::ChooseCapability(aConstraints, aPrefs, aDeviceId);
+  }
+
+}
+
 void
 MediaEngineRemoteVideoSource::GetCapability(size_t aIndex,
                                             webrtc::CaptureCapability& aOut)
 {
   if (!mHardcodedCapabilities.IsEmpty()) {
     MediaEngineCameraVideoSource::GetCapability(aIndex, aOut);
   }
   mozilla::camera::GetCaptureCapability(mCapEngine,
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -77,16 +77,20 @@ public:
   virtual void NotifyPull(MediaStreamGraph* aGraph,
                           SourceMediaStream* aSource,
                           TrackID aId,
                           StreamTime aDesiredTime) override;
   virtual const dom::MediaSourceEnum GetMediaSource() override {
     return mMediaSource;
   }
 
+  bool ChooseCapability(const dom::MediaTrackConstraints &aConstraints,
+                        const MediaEnginePrefs &aPrefs,
+                        const nsString& aDeviceId) override;
+
   void Refresh(int aIndex);
 
   virtual void Shutdown() override;
 
 protected:
   ~MediaEngineRemoteVideoSource() { Shutdown(); }
 
 private:
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -765,16 +765,26 @@ public class GeckoEvent {
     public static GeckoEvent createTelemetryHistogramAddEvent(String histogram,
                                                               int value) {
         GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_HISTOGRAM_ADD);
         event.mCharacters = histogram;
         event.mCount = value;
         return event;
     }
 
+    public static GeckoEvent createTelemetryKeyedHistogramAddEvent(String histogram,
+                                                                   String key,
+                                                                   int value) {
+        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_HISTOGRAM_ADD);
+        event.mCharacters = histogram;
+        event.mCharactersExtra = key;
+        event.mCount = value;
+        return event;
+    }
+
     public static GeckoEvent createTelemetryUISessionStartEvent(String session, long timestamp) {
         GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_UI_SESSION_START);
         event.mCharacters = session;
         event.mTime = timestamp;
         return event;
     }
 
     public static GeckoEvent createTelemetryUISessionStopEvent(String session, String reason, long timestamp) {
--- a/mobile/android/base/Telemetry.java
+++ b/mobile/android/base/Telemetry.java
@@ -38,16 +38,22 @@ public class Telemetry {
 
     // Define new histograms in:
     // toolkit/components/telemetry/Histograms.json
     public static void addToHistogram(String name, int value) {
         GeckoEvent event = GeckoEvent.createTelemetryHistogramAddEvent(name, value);
         GeckoAppShell.sendEventToGecko(event);
     }
 
+    public static void addToKeyedHistogram(String histogram, String keyName, int value) {
+        GeckoEvent event = GeckoEvent.createTelemetryKeyedHistogramAddEvent(histogram,
+                keyName, value);
+        GeckoAppShell.sendEventToGecko(event);
+    }
+
     public abstract static class Timer {
         private final long mStartTime;
         private final String mName;
 
         private volatile boolean mHasFinished;
         private volatile long mElapsed = -1;
 
         protected abstract long now();
--- a/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
@@ -171,21 +171,16 @@ public class FxAccountStatusActivity ext
   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
     int itemId = item.getItemId();
     if (itemId == android.R.id.home) {
       finish();
       return true;
     }
 
-    if (itemId == R.id.remove_account) {
-      maybeDeleteAndroidAccount(this, FirefoxAccounts.getFirefoxAccount(this), null);
-      return true;
-    }
-
     if (itemId == R.id.enable_debug_mode) {
       FxAccountUtils.LOG_PERSONAL_INFORMATION = !FxAccountUtils.LOG_PERSONAL_INFORMATION;
       Toast.makeText(this, (FxAccountUtils.LOG_PERSONAL_INFORMATION ? "Enabled" : "Disabled") +
           " Firefox Account personal information!", Toast.LENGTH_LONG).show();
       item.setChecked(!item.isChecked());
       // Display or hide debug options.
       statusFragment.hardRefresh();
       return true;
--- a/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
@@ -93,16 +93,17 @@ public class FxAccountStatusFragment
   // configured to use a custom Sync server. In debug mode, this is set.
   private static boolean ALWAYS_SHOW_SYNC_SERVER = false;
 
   protected PreferenceCategory accountCategory;
   protected Preference profilePreference;
   protected Preference emailPreference;
   protected Preference manageAccountPreference;
   protected Preference authServerPreference;
+  protected Preference removeAccountPreference;
 
   protected Preference needsPasswordPreference;
   protected Preference needsUpgradePreference;
   protected Preference needsVerificationPreference;
   protected Preference needsMasterSyncAutomaticallyEnabledPreference;
   protected Preference needsFinishMigratingPreference;
 
   protected PreferenceCategory syncCategory;
@@ -172,16 +173,17 @@ public class FxAccountStatusFragment
     } else {
       accountCategory.removePreference(profilePreference);
     }
     manageAccountPreference = ensureFindPreference("manage_account");
     if (AppConstants.MOZ_ANDROID_NATIVE_ACCOUNT_UI) {
       accountCategory.removePreference(manageAccountPreference);
     }
     authServerPreference = ensureFindPreference("auth_server");
+    removeAccountPreference = ensureFindPreference("remove_account");
 
     needsPasswordPreference = ensureFindPreference("needs_credentials");
     needsUpgradePreference = ensureFindPreference("needs_upgrade");
     needsVerificationPreference = ensureFindPreference("needs_verification");
     needsMasterSyncAutomaticallyEnabledPreference = ensureFindPreference("needs_master_sync_automatically_enabled");
     needsFinishMigratingPreference = ensureFindPreference("needs_finish_migrating");
 
     syncCategory = (PreferenceCategory) ensureFindPreference("sync_category");
@@ -200,16 +202,17 @@ public class FxAccountStatusFragment
     }
 
     if (AppConstants.MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES) {
       profilePreference.setOnPreferenceClickListener(this);
     } else {
       emailPreference.setOnPreferenceClickListener(this);
     }
     manageAccountPreference.setOnPreferenceClickListener(this);
+    removeAccountPreference.setOnPreferenceClickListener(this);
 
     needsPasswordPreference.setOnPreferenceClickListener(this);
     needsVerificationPreference.setOnPreferenceClickListener(this);
     needsFinishMigratingPreference.setOnPreferenceClickListener(this);
 
     bookmarksPreference.setOnPreferenceClickListener(this);
     historyPreference.setOnPreferenceClickListener(this);
     tabsPreference.setOnPreferenceClickListener(this);
@@ -250,16 +253,21 @@ public class FxAccountStatusFragment
     }
 
     if (preference == manageAccountPreference) {
       // There's no native equivalent, so no need to re-direct through an Intent filter.
       ActivityUtils.openURLInFennec(getActivity().getApplicationContext(), "about:accounts?action=manage");
       return true;
     }
 
+    if (preference == removeAccountPreference) {
+      FxAccountStatusActivity.maybeDeleteAndroidAccount(getActivity(), fxAccount.getAndroidAccount(), null);
+      return true;
+    }
+
     if (preference == needsPasswordPreference) {
       final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_UPDATE_CREDENTIALS);
       intent.putExtra(FxAccountWebFlowActivity.EXTRA_ENDPOINT, FxAccountConstants.ENDPOINT_PREFERENCES);
       final Bundle extras = getExtrasForAccount();
       if (extras != null) {
         intent.putExtras(extras);
       }
       // Per http://stackoverflow.com/a/8992365, this triggers a known bug with
--- a/mobile/android/base/locales/en-US/sync_strings.dtd
+++ b/mobile/android/base/locales/en-US/sync_strings.dtd
@@ -218,24 +218,24 @@
 <!ENTITY fxaccount_status_legal 'Legal' >
 <!-- Localization note: when tapped, the following two strings link to
      external web pages.  Compare fxaccount_policy_{linktos,linkprivacy}:
      these strings are separated to accommodate languages that decline
      the two uses differently. -->
 <!ENTITY fxaccount_status_linktos 'Terms of Service'>
 <!ENTITY fxaccount_status_linkprivacy 'Privacy Notice'>
 <!ENTITY fxaccount_status_more 'More&ellipsis;'>
+<!ENTITY fxaccount_remove_account 'Disconnect ...'>
 
 <!ENTITY fxaccount_remove_account_dialog_title 'Remove Firefox Account?'>
 <!ENTITY fxaccount_remove_account_dialog_message '&brandShortName; will stop syncing with your account, but won’t delete any of your browsing data on this device.'>
 <!-- Localization note: format string below will be replaced
      with the Firefox Account's email address. -->
 <!ENTITY fxaccount_remove_account_toast 'Firefox Account &formatS; removed.'>
 
-<!ENTITY fxaccount_remove_account_menu_item 'Remove Account'>
 <!ENTITY fxaccount_enable_debug_mode 'Enable Debug Mode'>
 
 <!-- Localization note: this is the name shown by the Android system
      itself for a Firefox Account. Don't localize this. -->
 <!ENTITY fxaccount_account_type_label 'Firefox'>
 
 <!-- Localization note: these are shown by the Android system itself,
      when the user navigates to the Android > Accounts > {Firefox
--- a/mobile/android/base/resources/menu/fxaccount_status_menu.xml
+++ b/mobile/android/base/resources/menu/fxaccount_status_menu.xml
@@ -1,11 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
   <item
-    android:id="@+id/remove_account"
-    android:title="@string/fxaccount_remove_account_menu_item" />
-  <item
       android:id="@+id/enable_debug_mode"
       android:checkable="true"
       android:checked="false"
       android:title="@string/fxaccount_enable_debug_mode" />
 </menu>
--- a/mobile/android/base/resources/xml/fxaccount_status_prefscreen.xml
+++ b/mobile/android/base/resources/xml/fxaccount_status_prefscreen.xml
@@ -97,17 +97,21 @@
             android:persistent="false"
             android:title="@string/fxaccount_status_device_name" />
 
         <Preference
             android:editable="false"
             android:key="sync_server"
             android:persistent="false"
             android:title="@string/fxaccount_status_sync_server" />
-
+        <Preference
+            android:editable="false"
+            android:key="remove_account"
+            android:persistent="false"
+            android:title="@string/fxaccount_remove_account" />
         <Preference
             android:editable="false"
             android:key="more"
             android:persistent="false"
             android:title="@string/fxaccount_status_more" />
 
     </PreferenceCategory>
     <PreferenceCategory
--- a/mobile/android/services/strings.xml.in
+++ b/mobile/android/services/strings.xml.in
@@ -206,16 +206,17 @@
 <string name="fxaccount_status_history">&fxaccount_status_history;</string>
 <string name="fxaccount_status_passwords">&fxaccount_status_passwords2;</string>
 <string name="fxaccount_status_tabs">&fxaccount_status_tabs;</string>
 <string name="fxaccount_status_reading_list">&reading_list_title;</string>
 <string name="fxaccount_status_legal">&fxaccount_status_legal;</string>
 <string name="fxaccount_status_linktos">&fxaccount_status_linktos;</string>
 <string name="fxaccount_status_linkprivacy">&fxaccount_status_linkprivacy;</string>
 <string name="fxaccount_status_more">&fxaccount_status_more;</string>
+<string name="fxaccount_remove_account">&fxaccount_remove_account;</string>
 
 <string name="fxaccount_label">&fxaccount_account_type_label;</string>
 
 <string name="fxaccount_options_title">&fxaccount_options_title;</string>
 <string name="fxaccount_options_configure_title">&fxaccount_options_configure_title;</string>
 
 <string name="fxaccount_remote_error_UPGRADE_REQUIRED">&fxaccount_remote_error_UPGRADE_REQUIRED;</string>
 <string name="fxaccount_remote_error_ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS">&fxaccount_remote_error_ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS_2;</string>
@@ -230,15 +231,14 @@
 
 <string name="fxaccount_sync_sign_in_error_notification_title">&fxaccount_sync_sign_in_error_notification_title2;</string>
 <string name="fxaccount_sync_sign_in_error_notification_text">&fxaccount_sync_sign_in_error_notification_text2;</string>
 
 <!-- Remove Account -->
 <string name="fxaccount_remove_account_dialog_title">&fxaccount_remove_account_dialog_title;</string>
 <string name="fxaccount_remove_account_dialog_message">&fxaccount_remove_account_dialog_message;</string>
 <string name="fxaccount_remove_account_toast">&fxaccount_remove_account_toast;</string>
-<string name="fxaccount_remove_account_menu_item">&fxaccount_remove_account_menu_item;</string>
 
 <string name="fxaccount_sync_finish_migrating_notification_title">&fxaccount_sync_finish_migrating_notification_title;</string>
 <string name="fxaccount_sync_finish_migrating_notification_text">&fxaccount_sync_finish_migrating_notification_text;</string>
 
 <!-- Log Personal information -->
 <string name="fxaccount_enable_debug_mode">&fxaccount_enable_debug_mode;</string>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3265,16 +3265,21 @@ pref("ui.osk.enabled", true);
 // Only show the on-screen keyboard if there are no physical keyboards attached
 // to the device.
 pref("ui.osk.detect_physical_keyboard", true);
 // Path to TabTip.exe on local machine. Cached for performance reasons.
 pref("ui.osk.on_screen_keyboard_path", "");
 // Only show the on-screen keyboard when Windows is in Tablet mode. Setting
 // this pref to false will allow the OSK to show in regular non-tablet mode.
 pref("ui.osk.require_tablet_mode", true);
+// This pref stores the "reason" that the on-screen keyboard was either
+// shown or not shown when focus is moved to an editable text field. It is
+// used to help debug why the keyboard is either not appearing when expected
+// or appearing when it is not expected.
+pref("ui.osk.debug.keyboardDisplayReason", "");
 
 # XP_WIN
 #endif
 
 #ifdef XP_MACOSX
 // Mac specific preference defaults
 pref("browser.drag_out_of_frame_style", 1);
 pref("ui.key.saveLink.shift", false); // true = shift, false = meta
--- a/testing/taskcluster/tasks/branches/base_job_flags.yml
+++ b/testing/taskcluster/tasks/branches/base_job_flags.yml
@@ -11,17 +11,16 @@ flags:
     - emulator-kk
     - emulator-x86-kk
     - emulator-l
     - linux32_gecko  # b2g desktop linux 32 bit
     - linux64_gecko  # b2g desktop linux 64 bit
     - linux64-mulet  # Firefox desktop - b2g gecko linux 64 bit
     - macosx64_gecko # b2g desktop osx 64 bit
     - win32_gecko    # b2g desktop win 32 bit
-    - flame-kk-ota
     - flame-kk       # b2g flame kitkat
     - flame-kk-eng   # b2g flame eng build
     - flame-kk-spark-eng
     - nexus-4
     - nexus-4-eng
     - nexus-4-kk
     - nexus-4-kk-eng
     - nexus-5l
--- a/testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml
+++ b/testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml
@@ -26,22 +26,8 @@ builds:
   aries-ota:
     platforms:
       - b2g
     types:
       opt:
         task: tasks/builds/b2g_aries_spark_ota_opt.yml
       debug:
         task: tasks/builds/b2g_aries_spark_ota_debug.yml
-  flame-kk-ota:
-    platforms:
-      - b2g
-    types:
-      opt:
-        task: tasks/builds/b2g_flame_kk_ota_opt.yml
-      debug:
-        task: tasks/builds/b2g_flame_kk_ota_debug.yml
-
-post-build:
-  simulator:
-    allowed_build_tasks:
-      - tasks/builds/mulet_linux.yml
-    task: tasks/post-builds/mulet_simulator.yml
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -3720,16 +3720,29 @@ Accumulate(const char* name, uint32_t sa
   Histogram *h;
   rv = GetHistogramByEnumId(id, &h);
   if (NS_SUCCEEDED(rv)) {
     HistogramAdd(*h, sample, gHistograms[id].dataset);
   }
 }
 
 void
+Accumulate(const char *name, const nsCString& key, uint32_t sample)
+{
+    if (!TelemetryImpl::CanRecordBase()) {
+      return;
+    }
+    ID id;
+    nsresult rv = TelemetryImpl::GetHistogramEnumId(name, &id);
+    if (NS_SUCCEEDED(rv)) {
+      Accumulate(id, key, sample);
+    }
+}
+
+void
 AccumulateTimeDelta(ID aHistogram, TimeStamp start, TimeStamp end)
 {
   Accumulate(aHistogram,
              static_cast<uint32_t>((end - start).ToMilliseconds()));
 }
 
 bool
 CanRecordBase()
--- a/toolkit/components/telemetry/Telemetry.h
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -58,16 +58,28 @@ void Accumulate(ID id, const nsCString& 
  * certainly be using the by-enum-id version instead of this one.
  *
  * @param name - histogram name
  * @param sample - value to record
  */
 void Accumulate(const char* name, uint32_t sample);
 
 /**
+ * Adds a sample to a histogram defined in TelemetryHistograms.h.
+ * This function is here to support telemetry measurements from Java,
+ * where we have only names and not numeric IDs.  You should almost
+ * certainly be using the by-enum-id version instead of this one.
+ *
+ * @param name - histogram name
+ * @param key - the string key
+ * @param sample - sample - (optional) value to record, defaults to 1.
+ */
+void Accumulate(const char *name, const nsCString& key, uint32_t sample = 1);
+
+/**
  * Adds time delta in milliseconds to a histogram defined in TelemetryHistograms.h
  *
  * @param id - histogram id
  * @param start - start time
  * @param end - end time
  */
 void AccumulateTimeDelta(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
 
--- a/toolkit/content/aboutwebrtc/aboutWebrtc.js
+++ b/toolkit/content/aboutwebrtc/aboutWebrtc.js
@@ -519,20 +519,19 @@ RTPStats.prototype = {
       statsString = label + statsString;
     }
 
     let line = document.createElement("p");
     line.textContent = statsString;
     return line;
   },
 
-  renderTransportStats: function(stats, type) {
-    let label = this.labelize(type);
+  renderTransportStats: function(stats, typeLabel) {
     let time  = new Date(stats.timestamp).toTimeString();
-    let statsString = `${label}: ${time} ${stats.type} SSRC: ${stats.ssrc}`;
+    let statsString = `${typeLabel}: ${time} ${stats.type} SSRC: ${stats.ssrc}`;
 
     if (stats.packetsReceived) {
       statsString += ` ${getString("received_label")}: ${stats.packetsReceived} ${getString("packets")}`;
 
       if (stats.bytesReceived) {
         statsString += ` (${(stats.bytesReceived / 1024).toFixed(2)} Kb)`;
       }
 
@@ -560,28 +559,24 @@ RTPStats.prototype = {
     heading.textContent = stats.id;
     div.appendChild(heading);
 
     if (stats.MozAvSyncDelay || stats.mozJitterBufferDelay) {
       div.appendChild(this.renderAvStats(stats));
     }
 
     div.appendChild(this.renderCoderStats(stats));
-    div.appendChild(this.renderTransportStats(stats, getString("local")));
+    div.appendChild(this.renderTransportStats(stats, getString("typeLocal")));
 
     if (stats.remoteId && stats.remoteRtpStats) {
-      div.appendChild(this.renderTransportStats(stats.remoteRtpStats, getString("remote")));
+      div.appendChild(this.renderTransportStats(stats.remoteRtpStats, getString("typeRemote")));
     }
 
     return div;
   },
-
-  labelize: function(label) {
-    return `${label.charAt(0).toUpperCase()}${label.slice(1)}`;
-  }
 };
 
 function ICEStats(report) {
   this._report = report;
 }
 
 ICEStats.prototype = {
   render: function() {
--- a/toolkit/locales/en-US/chrome/global/aboutWebrtc.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutWebrtc.properties
@@ -71,21 +71,21 @@ av_sync_label = A/V sync
 # This is used as a data label.
 jitter_buffer_delay_label = Jitter-buffer delay
 
 # LOCALIZATION NOTE (avg_bitrate_label, avg_framerate_label): "Avg." is an abbreviation
 # for Average. These are used as data labels.
 avg_bitrate_label = Avg. bitrate
 avg_framerate_label = Avg. framerate
 
-# LOCALIZATION NOTE (local, remote): These adjectives are used to label a
+# LOCALIZATION NOTE (typeLocal, typeRemote): These adjectives are used to label a
 # line of statistics collected for a peer connection. The data represents
 # either the local or remote end of the connection.
-local = local
-remote = remote
+typeLocal = Local
+typeRemote = Remote
 
 # LOCALIZATION NOTE (nominated): This adjective is used to label a table column.
 # Cells in this column contain the localized javascript string representation of "true"
 # or are left blank.
 nominated = Nominated
 
 # LOCALIZATION NOTE (selected): This adjective is used to label a table column.
 # Cells in this column contain the localized javascript string representation of "true"
--- a/toolkit/locales/en-US/chrome/global/devtools/gclicommands.properties
+++ b/toolkit/locales/en-US/chrome/global/devtools/gclicommands.properties
@@ -91,25 +91,25 @@ screenshotAdvancedOptions=Advanced Optio
 # a dialog when the user is using this command.
 screenshotDelayDesc=Delay (seconds)
 
 # LOCALIZATION NOTE (screenshotDelayManual) A fuller description of the
 # 'delay' parameter to the 'screenshot' command, displayed when the user
 # asks for help on what it does.
 screenshotDelayManual=The time to wait (in seconds) before the screenshot is taken
 
-# LOCALIZATION NOTE (screenshotDPIDesc) A very short string to describe
-# the 'dpi' parameter to the 'screenshot' command, which is displayed in
+# LOCALIZATION NOTE (screenshotDPRDesc) A very short string to describe
+# the 'dpr' parameter to the 'screenshot' command, which is displayed in
 # a dialog when the user is using this command.
-screenshotDPIDesc=Dots per inch
+screenshotDPRDesc=Device pixel ratio
 
-# LOCALIZATION NOTE (screenshotDPIManual) A fuller description of the
-# 'dpi' parameter to the 'screenshot' command, displayed when the user
+# LOCALIZATION NOTE (screenshotDPRManual) A fuller description of the
+# 'dpr' parameter to the 'screenshot' command, displayed when the user
 # asks for help on what it does.
-screenshotDPIManual=The number of dots per inch in the screenshot
+screenshotDPRManual=The device pixel ratio to use when taking the screenshot
 
 # LOCALIZATION NOTE (screenshotFullscreenDesc) A very short string to describe
 # the 'fullscreen' parameter to the 'screenshot' command, which is displayed in
 # a dialog when the user is using this command.
 screenshotFullPageDesc=Entire webpage? (true/false)
 
 # LOCALIZATION NOTE (screenshotFullscreenManual) A fuller description of the
 # 'fullscreen' parameter to the 'screenshot' command, displayed when the user
--- a/toolkit/modules/Troubleshoot.jsm
+++ b/toolkit/modules/Troubleshoot.jsm
@@ -84,16 +84,20 @@ const PREFS_WHITELIST = [
   "plugins.",
   "print.",
   "privacy.",
   "security.",
   "social.enabled",
   "storage.vacuum.last.",
   "svg.",
   "toolkit.startup.recent_crashes",
+  "ui.osk.enabled",
+  "ui.osk.detect_physical_keyboard",
+  "ui.osk.require_tablet_mode",
+  "ui.osk.debug.keyboardDisplayReason",
   "webgl.",
 ];
 
 // The blacklist, unlike the whitelist, is a list of regular expressions.
 const PREFS_BLACKLIST = [
   /^network[.]proxy[.]/,
   /[.]print_to_filename$/,
   /^print[.]macosx[.]pagesetup/,
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -548,16 +548,17 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
 
         case NETWORK_LINK_CHANGE: {
             ReadCharactersField(jenv);
             break;
         }
 
         case TELEMETRY_HISTOGRAM_ADD: {
             ReadCharactersField(jenv);
+            ReadCharactersExtraField(jenv);
             mCount = jenv->GetIntField(jobj, jCountField);
             break;
         }
 
         case TELEMETRY_UI_SESSION_START: {
             ReadCharactersField(jenv);
             mTime = jenv->GetLongField(jobj, jTimeField);
             break;
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -727,18 +727,25 @@ nsAppShell::LegacyGeckoEvent::Run()
             os->NotifyObservers(nullptr,
                                 NS_NETWORK_LINK_TOPIC,
                                 nsString(curEvent->Characters()).get());
         }
         break;
     }
 
     case AndroidGeckoEvent::TELEMETRY_HISTOGRAM_ADD:
-        Telemetry::Accumulate(NS_ConvertUTF16toUTF8(curEvent->Characters()).get(),
-                              curEvent->Count());
+        // If the extras field is not empty then this is a keyed histogram.
+        if (!curEvent->CharactersExtra().IsVoid()) {
+            Telemetry::Accumulate(NS_ConvertUTF16toUTF8(curEvent->Characters()).get(),
+                                  NS_ConvertUTF16toUTF8(curEvent->CharactersExtra()),
+                                  curEvent->Count());
+        } else {
+            Telemetry::Accumulate(NS_ConvertUTF16toUTF8(curEvent->Characters()).get(),
+                                  curEvent->Count());
+        }
         break;
 
     case AndroidGeckoEvent::GAMEPAD_ADDREMOVE: {
 #ifdef MOZ_GAMEPAD
             if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_ADDED) {
             int svc_id = dom::GamepadFunctions::AddGamepad("android",
                                                            dom::GamepadMappingType::Standard,
                                                            dom::kStandardGamepadButtons,
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -24,16 +24,17 @@
 #include "powrprof.h"
 #include "setupapi.h"
 #include "cfgmgr32.h"
 
 const char* kOskPathPrefName = "ui.osk.on_screen_keyboard_path";
 const char* kOskEnabled = "ui.osk.enabled";
 const char* kOskDetectPhysicalKeyboard = "ui.osk.detect_physical_keyboard";
 const char* kOskRequireTabletMode = "ui.osk.require_tablet_mode";
+const char* kOskDebugReason = "ui.osk.debug.keyboardDisplayReason";
 
 namespace mozilla {
 namespace widget {
 
 /******************************************************************************
  * IMEHandler
  ******************************************************************************/
 
@@ -542,17 +543,17 @@ IMEHandler::MaybeShowOnScreenKeyboard()
   // run on Windows 8 and higher (adjusting the IsWin10OrLater
   // guard above and within MaybeDismissOnScreenKeyboard).
   if (!IsInTabletMode() &&
       Preferences::GetBool(kOskRequireTabletMode, true) &&
       !AutoInvokeOnScreenKeyboardInDesktopMode()) {
     return;
   }
 
- IMEHandler::ShowOnScreenKeyboard();
+  IMEHandler::ShowOnScreenKeyboard();
 }
 
 // static
 void
 IMEHandler::MaybeDismissOnScreenKeyboard()
 {
   if (sPluginHasFocus ||
       !IsWin10OrLater() ||
@@ -585,32 +586,36 @@ IMEHandler::WStringStartsWithCaseInsensi
 // are attached to the machine.
 // Based on IsKeyboardPresentOnSlate() in Chromium's base/win/win_util.cc.
 // static
 bool
 IMEHandler::IsKeyboardPresentOnSlate()
 {
   // This function is only supported for Windows 8 and up.
   if (!IsWin8OrLater()) {
+    Preferences::SetString(kOskDebugReason, L"IKPOS: Requires Win8+.");
     return true;
   }
 
   if (!Preferences::GetBool(kOskDetectPhysicalKeyboard, true)) {
-    // Detection for physical keyboard has been disabled for testing.
+    Preferences::SetString(kOskDebugReason, L"IKPOS: Detection disabled.");
     return false;
   }
 
   // This function should be only invoked for machines with touch screens.
   if ((::GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH)
         != NID_INTEGRATED_TOUCH) {
+    Preferences::SetString(kOskDebugReason,
+                           L"IKPOS: Touch screen not found.");
     return true;
   }
 
   // If the device is docked, the user is treating the device as a PC.
   if (::GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
+    Preferences::SetString(kOskDebugReason, L"IKPOS: System docked.");
     return true;
   }
 
   // To determine whether a keyboard is present on the device, we do the
   // following:-
   // 1. Check whether the device supports auto rotation. If it does then
   //    it possibly supports flipping from laptop to slate mode. If it
   //    does not support auto rotation, then we assume it is a desktop
@@ -627,50 +632,61 @@ IMEHandler::IsKeyboardPresentOnSlate()
   typedef BOOL (WINAPI* GetAutoRotationState)(PAR_STATE state);
   GetAutoRotationState get_rotation_state =
     reinterpret_cast<GetAutoRotationState>(::GetProcAddress(
       ::GetModuleHandleW(L"user32.dll"), "GetAutoRotationState"));
 
   if (get_rotation_state) {
     AR_STATE auto_rotation_state = AR_ENABLED;
     get_rotation_state(&auto_rotation_state);
-    if ((auto_rotation_state & AR_NOSENSOR) ||
-        (auto_rotation_state & AR_NOT_SUPPORTED)) {
-      // If there is no auto rotation sensor or rotation is not supported in
-      // the current configuration, then we can assume that this is a desktop
-      // or a traditional laptop.
+    // If there is no auto rotation sensor or rotation is not supported in
+    // the current configuration, then we can assume that this is a desktop
+    // or a traditional laptop.
+    if (auto_rotation_state & AR_NOSENSOR) {
+      Preferences::SetString(kOskDebugReason,
+                             L"IKPOS: Rotation sensor not found.");
+      return true;
+    } else if (auto_rotation_state & AR_NOT_SUPPORTED) {
+      Preferences::SetString(kOskDebugReason,
+                             L"IKPOS: Auto-rotation not supported.");
       return true;
     }
   }
 
   // Check if the device is being used as a laptop or a tablet. This can be
   // checked by first checking the role of the device and then the
   // corresponding system metric (SM_CONVERTIBLESLATEMODE). If it is being
   // used as a tablet then we want the OSK to show up.
   typedef POWER_PLATFORM_ROLE (WINAPI* PowerDeterminePlatformRole)();
   PowerDeterminePlatformRole power_determine_platform_role =
     reinterpret_cast<PowerDeterminePlatformRole>(::GetProcAddress(
       ::LoadLibraryW(L"PowrProf.dll"), "PowerDeterminePlatformRole"));
   if (power_determine_platform_role) {
     POWER_PLATFORM_ROLE role = power_determine_platform_role();
     if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) &&
          (::GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0)) {
+      if (role == PlatformRoleMobile) {
+        Preferences::SetString(kOskDebugReason, L"IKPOS: PlatformRoleMobile.");
+      } else if (role == PlatformRoleSlate) {
+        Preferences::SetString(kOskDebugReason, L"IKPOS: PlatformRoleSlate.");
+      }
       return false;
     }
   }
 
   const GUID KEYBOARD_CLASS_GUID =
     { 0x4D36E96B, 0xE325,  0x11CE,
       { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
 
   // Query for all the keyboard devices.
   HDEVINFO device_info =
     ::SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, nullptr,
                           nullptr, DIGCF_PRESENT);
   if (device_info == INVALID_HANDLE_VALUE) {
+    Preferences::SetString(kOskDebugReason, L"IKPOS: No keyboard info.");
     return false;
   }
 
   // Enumerate all keyboards and look for ACPI\PNP and HID\VID devices. If
   // the count is more than 1 we assume that a keyboard is present. This is
   // under the assumption that there will always be one keyboard device.
   for (DWORD i = 0;; ++i) {
     SP_DEVINFO_DATA device_info_data = { 0 };
@@ -691,63 +707,85 @@ IMEHandler::IsKeyboardPresentOnSlate()
       if (IMEHandler::WStringStartsWithCaseInsensitive(device_id,
                                                        L"ACPI") ||
           IMEHandler::WStringStartsWithCaseInsensitive(device_id,
                                                        L"HID\\VID")) {
         // The heuristic we are using is to check the count of keyboards and
         // return true if the API's report one or more keyboards. Please note
         // that this will break for non keyboard devices which expose a
         // keyboard PDO.
+        Preferences::SetString(kOskDebugReason,
+                               L"IKPOS: Keyboard presence confirmed.");
         return true;
       }
     }
   }
+  Preferences::SetString(kOskDebugReason,
+                         L"IKPOS: Lack of keyboard confirmed.");
   return false;
 }
 
 // static
 bool
 IMEHandler::IsInTabletMode()
 {
   nsCOMPtr<nsIWindowsUIUtils>
     uiUtils(do_GetService("@mozilla.org/windows-ui-utils;1"));
   if (NS_WARN_IF(!uiUtils)) {
+    Preferences::SetString(kOskDebugReason,
+                           L"IITM: nsIWindowsUIUtils not available.");
     return false;
   }
   bool isInTabletMode = false;
   uiUtils->GetInTabletMode(&isInTabletMode);
+  if (isInTabletMode) {
+    Preferences::SetString(kOskDebugReason, L"IITM: GetInTabletMode=true.");
+  } else {
+    Preferences::SetString(kOskDebugReason, L"IITM: GetInTabletMode=false.");
+  }
   return isInTabletMode;
 }
 
 // static
 bool
 IMEHandler::AutoInvokeOnScreenKeyboardInDesktopMode()
 {
   nsresult rv;
   nsCOMPtr<nsIWindowsRegKey> regKey
     (do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
   if (NS_WARN_IF(NS_FAILED(rv))) {
+    Preferences::SetString(kOskDebugReason, L"AIOSKIDM: "
+                           L"nsIWindowsRegKey not available");
     return false;
   }
   rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
                     NS_LITERAL_STRING("SOFTWARE\\Microsoft\\TabletTip\\1.7"),
                     nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   if (NS_FAILED(rv)) {
+    Preferences::SetString(kOskDebugReason,
+                           L"AIOSKIDM: failed opening regkey.");
     return false;
   }
   // EnableDesktopModeAutoInvoke is an opt-in option from the Windows
   // Settings to "Automatically show the touch keyboard in windowed apps
   // when there's no keyboard attached to your device." If the user has
   // opted-in to this behavior, the tablet-mode requirement is skipped.
   uint32_t value;
   rv = regKey->ReadIntValue(NS_LITERAL_STRING("EnableDesktopModeAutoInvoke"),
                             &value);
   if (NS_FAILED(rv)) {
+    Preferences::SetString(kOskDebugReason,
+                           L"AIOSKIDM: failed reading value of regkey.");
     return false;
   }
+  if (!!value) {
+    Preferences::SetString(kOskDebugReason, L"AIOSKIDM: regkey value=true.");
+  } else {
+    Preferences::SetString(kOskDebugReason, L"AIOSKIDM: regkey value=false.");
+  }
   return !!value;
 }
 
 // Based on DisplayVirtualKeyboard() in Chromium's base/win/win_util.cc.
 // static
 void
 IMEHandler::ShowOnScreenKeyboard()
 {