Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Thu, 08 Oct 2015 14:35:43 -0700
changeset 288166 1a5167cd76888a6cfe7d94ab333fe444c7b0681b
parent 288165 fd660e3112d6f2f1d9d121450eaff6ed1ac31a76 (current diff)
parent 288065 e5f1bc63ad52d0eb86f7fb838226ca6036774660 (diff)
child 288167 bf388a8e620ba36cbb15fd3393d2c67838096531
push id8654
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:48:40 +0000
treeherdermozilla-aurora@bc4551debe17 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone44.0a1
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()
 {