Merge m-c to inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 15 Aug 2014 17:04:03 -0400
changeset 199877 baea646f5a80c0cb1b3121b55471255ccffddc4a
parent 199820 84845cf0f3987ff9ec57496b3c1b251a53869bcf (current diff)
parent 199876 174e75a23eaf579ec9700f72c2bac8054f365be4 (diff)
child 199878 9acca266d2c8ebc84e80e3eaaa0a43da32165d58
push id47750
push userryanvm@gmail.com
push dateFri, 15 Aug 2014 21:04:12 +0000
treeherdermozilla-inbound@baea646f5a80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound. a=merge
browser/components/loop/test/mochitest/browser_mozLoop_charPref.js
browser/components/loop/test/xpcshell/test_loopservice_get_loop_char_pref.js
browser/components/loop/test/xpcshell/test_loopservice_set_loop_char_pref.js
browser/themes/linux/in-content/common.css
browser/themes/osx/in-content/common.css
browser/themes/shared/in-content/check.png
browser/themes/shared/in-content/check@2x.png
browser/themes/shared/in-content/common.inc.css
browser/themes/shared/in-content/dropdown-disabled.png
browser/themes/shared/in-content/dropdown-disabled@2x.png
browser/themes/shared/in-content/dropdown.png
browser/themes/shared/in-content/dropdown@2x.png
browser/themes/shared/in-content/help-glyph.png
browser/themes/shared/in-content/help-glyph@2x.png
browser/themes/shared/in-content/sorter.png
browser/themes/shared/in-content/sorter@2x.png
browser/themes/windows/in-content/common.css
mobile/android/base/home/SuggestClient.java
mobile/android/search/java/org/mozilla/search/autocomplete/SuggestClient.java
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--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="3aa6abd313f965a84aa86c6b213dc154e4875139">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="7945ca73e687be5edbc7b928dc7fe3a208242144">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <!-- 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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--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="3aa6abd313f965a84aa86c6b213dc154e4875139">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "87505dbb861f8c1e5437bcf92cc5a0040e6fdf3f", 
+    "revision": "0cf972fdd11ec591d6a1dd4a8139e2703c40f1e1", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--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="3aa6abd313f965a84aa86c6b213dc154e4875139">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="d0d773c277a9105288ee35da2121f4ae62709be8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fe933e0c958f80b241a9b580cad980ff1338b038"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1275,18 +1275,18 @@ pref("devtools.toolbar.enabled", true);
 pref("devtools.toolbar.visible", false);
 pref("devtools.commands.dir", "");
 
 // Enable the app manager
 pref("devtools.appmanager.enabled", true);
 pref("devtools.appmanager.lastTab", "help");
 pref("devtools.appmanager.manifestEditor.enabled", true);
 
-// Disable devtools webide until bug 1007059
-pref("devtools.webide.enabled", false);
+// Enable DevTools WebIDE by default
+pref("devtools.webide.enabled", true);
 
 // Toolbox preferences
 pref("devtools.toolbox.footer.height", 250);
 pref("devtools.toolbox.sidebar.width", 500);
 pref("devtools.toolbox.host", "bottom");
 pref("devtools.toolbox.selectedTool", "webconsole");
 pref("devtools.toolbox.toolbarSpec", '["splitconsole", "paintflashing toggle","tilt toggle","scratchpad","resize toggle","eyedropper","screenshot --fullpage"]');
 pref("devtools.toolbox.sideEnabled", true);
--- a/browser/base/content/aboutneterror/netError.css
+++ b/browser/base/content/aboutneterror/netError.css
@@ -1,13 +1,13 @@
 /* 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/. */
 
-@import url("chrome://browser/skin/in-content/common.css");
+@import url("chrome://global/skin/in-content/common.css");
 
 body {
   display: flex;
   box-sizing: padding-box;
   min-height: 100vh;
   padding: 0 48px;
   align-items: center;
   justify-content: center;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -18,16 +18,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
                                   "resource://gre/modules/CharsetMenu.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
                                   "resource://gre/modules/ShortcutUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "GMPInstallManager",
                                   "resource://gre/modules/GMPInstallManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
+                                  "resource:///modules/ContentSearch.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
+                                  "resource:///modules/AboutHome.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
                                    "@mozilla.org/network/dns-service;1",
                                    "nsIDNSService");
 
 const nsIWebNavigation = Ci.nsIWebNavigation;
 
 var gLastBrowserCharset = null;
 var gProxyFavIcon = null;
@@ -3088,18 +3092,27 @@ const BrowserSearch = {
         win = window.openDialog(getBrowserURL(), "_blank",
                                 "chrome,all,dialog=no", "about:blank");
         Services.obs.addObserver(observer, "browser-delayed-startup-finished", false);
       }
       return;
     }
 #endif
     let openSearchPageIfFieldIsNotActive = function(aSearchBar) {
-      if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField)
+      let doc = gBrowser.selectedBrowser.contentDocument;
+      let url = doc.documentURI.toLowerCase();
+      let mm = gBrowser.selectedBrowser.messageManager;
+
+      if (url === "about:home") {
+        AboutHome.focusInput(mm);
+      } else if (url === "about:newtab") {
+        ContentSearch.focusInput(mm);
+      } else if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) {
         openUILinkIn("about:home", "current");
+      }
     };
 
     let searchBar = this.searchBar;
     let placement = CustomizableUI.getPlacementOfWidget("search-container");
     let focusSearchBar = () => {
       searchBar = this.searchBar;
       searchBar.select();
       openSearchPageIfFieldIsNotActive(searchBar);
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -101,16 +101,19 @@ let AboutHomeListener = {
     }
   },
 
   receiveMessage: function(aMessage) {
     switch (aMessage.name) {
       case "AboutHome:Update":
         this.onUpdate(aMessage.data);
         break;
+      case "AboutHome:FocusInput":
+        this.onFocusInput();
+        break;
     }
   },
 
   onUpdate: function(aData) {
     let doc = content.document;
     if (doc.documentURI.toLowerCase() != "about:home")
       return;
 
@@ -133,16 +136,17 @@ let AboutHomeListener = {
     if (doc.documentURI.toLowerCase() != "about:home" ||
         doc.documentElement.hasAttribute("hasBrowserHandlers")) {
       return;
     }
 
     doc.documentElement.setAttribute("hasBrowserHandlers", "true");
     let self = this;
     addMessageListener("AboutHome:Update", self);
+    addMessageListener("AboutHome:FocusInput", self);
     addEventListener("click", this.onClick, true);
     addEventListener("pagehide", function onPageHide(event) {
       if (event.target.defaultView.frameElement)
         return;
       removeMessageListener("AboutHome:Update", self);
       removeEventListener("click", self.onClick, true);
       removeEventListener("pagehide", onPageHide, true);
       if (event.target.documentElement)
@@ -207,16 +211,20 @@ let AboutHomeListener = {
         sendAsyncMessage("AboutHome:Sync");
         break;
 
       case "settings":
         sendAsyncMessage("AboutHome:Settings");
         break;
     }
   },
+
+  onFocusInput: function () {
+    content.document.getElementById("searchText").focus();
+  },
 };
 AboutHomeListener.init(this);
 
 
 // An event listener for custom "WebChannelMessageToChrome" events on pages
 addEventListener("WebChannelMessageToChrome", function (e) {
   // if target is window then we want the document principal, otherwise fallback to target itself.
   let principal = e.target.nodePrincipal ? e.target.nodePrincipal : e.target.document.nodePrincipal;
--- a/browser/base/content/newtab/search.js
+++ b/browser/base/content/newtab/search.js
@@ -71,16 +71,20 @@ let gSearch = {
 
   onCurrentEngine: function (engineName) {
     if (this._initialStateReceived) {
       this._nodes.panel.hidePopup();
       this._setCurrentEngine(engineName);
     }
   },
 
+  onFocusInput: function () {
+    this._nodes.text.focus();
+  },
+
   _nodeIDSuffixes: [
     "form",
     "logo",
     "manage",
     "panel",
     "text",
   ],
 
--- a/browser/base/content/test/general/browser_aboutHome.js
+++ b/browser/base/content/test/general/browser_aboutHome.js
@@ -414,16 +414,32 @@ let gTests = [
 
       // Empty the search input, causing the suggestions to be hidden.
       EventUtils.synthesizeKey("a", { accelKey: true });
       EventUtils.synthesizeKey("VK_DELETE", {});
       ok(table.hidden, "Search suggestion table hidden");
     });
   }
 },
+{
+  desc: "Cmd+k should focus the search bar element",
+  setup: function () {},
+  run: Task.async(function* () {
+    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
+    let logo = doc.getElementById("brandLogo");
+    let searchInput = doc.getElementById("searchText");
+
+    EventUtils.synthesizeMouseAtCenter(logo, {});
+    isnot(searchInput, doc.activeElement, "Search input should not be the active element.");
+
+    EventUtils.synthesizeKey("k", { accelKey: true });
+    yield promiseWaitForCondition(() => doc.activeElement === searchInput);
+    is(searchInput, doc.activeElement, "Search input should be the active element.");
+  })
+},
 
 ];
 
 function test()
 {
   waitForExplicitFinish();
   requestLongerTimeout(2);
   ignoreAllUncaughtExceptions();
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -77,16 +77,22 @@ function waitForCondition(condition, nex
     if (conditionPassed) {
       moveOn();
     }
     tries++;
   }, 100);
   var moveOn = function() { clearInterval(interval); nextTest(); };
 }
 
+function promiseWaitForCondition(aConditionFn) {
+  let deferred = Promise.defer();
+  waitForCondition(aConditionFn, deferred.resolve, "Condition didn't pass.");
+  return deferred.promise;
+}
+
 function getTestPlugin(aName) {
   var pluginName = aName || "Test Plug-in";
   var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
   var tags = ph.getPluginTags();
 
   // Find the test plugin
   for (var i = 0; i < tags.length; i++) {
     if (tags[i].name == pluginName)
--- a/browser/base/content/test/newtab/browser_newtab_search.js
+++ b/browser/base/content/test/newtab/browser_newtab_search.js
@@ -181,16 +181,26 @@ function runTests() {
   yield undefined;
   yield suggestionsPromise.then(TestRunner.next);
 
   // Empty the search input, causing the suggestions to be hidden.
   EventUtils.synthesizeKey("a", { accelKey: true });
   EventUtils.synthesizeKey("VK_DELETE", {});
   ok(table.hidden, "Search suggestion table hidden");
 
+  // Focus a different element than the search input.
+  let btn = getContentDocument().getElementById("newtab-customize-button");
+  yield promiseClick(btn).then(TestRunner.next);
+
+  isnot(input, getContentDocument().activeElement, "Search input should not be focused");
+  // Test that Ctrl/Cmd + K will focus the input field.
+  EventUtils.synthesizeKey("k", { accelKey: true });
+  yield promiseSearchEvents(["FocusInput"]).then(TestRunner.next);
+  is(input, getContentDocument().activeElement, "Search input should be focused");
+
   // Done.  Revert the current engine and remove the new engines.
   Services.search.currentEngine = oldCurrentEngine;
   yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
 
   let events = [];
   for (let engine of gNewEngines) {
     Services.search.removeEngine(engine);
     events.push("CurrentState");
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -304,16 +304,18 @@ function openLinkIn(url, where, params) 
       loadInBackground = false;
     }
   }
 
   // Raise the target window before loading the URI, since loading it may
   // result in a new frontmost window (e.g. "javascript:window.open('');").
   w.focus();
 
+  let newTab;
+
   switch (where) {
   case "current":
     let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
 
     if (aAllowThirdPartyFixup) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
     }
@@ -327,32 +329,39 @@ function openLinkIn(url, where, params) 
 
     w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData);
     break;
   case "tabshifted":
     loadInBackground = !loadInBackground;
     // fall through
   case "tab":
     let browser = w.gBrowser;
-    browser.loadOneTab(url, {
-                       referrerURI: aReferrerURI,
-                       charset: aCharset,
-                       postData: aPostData,
-                       inBackground: loadInBackground,
-                       allowThirdPartyFixup: aAllowThirdPartyFixup,
-                       relatedToCurrent: aRelatedToCurrent,
-                       skipAnimation: aSkipTabAnimation,
-                       allowMixedContent: aAllowMixedContent });
+    newTab = browser.loadOneTab(url, {
+                                referrerURI: aReferrerURI,
+                                charset: aCharset,
+                                postData: aPostData,
+                                inBackground: loadInBackground,
+                                allowThirdPartyFixup: aAllowThirdPartyFixup,
+                                relatedToCurrent: aRelatedToCurrent,
+                                skipAnimation: aSkipTabAnimation,
+                                allowMixedContent: aAllowMixedContent });
     break;
   }
 
   w.gBrowser.selectedBrowser.focus();
 
-  if (!loadInBackground && w.isBlankPageURL(url))
+  if (!loadInBackground && w.isBlankPageURL(url)) {
+    if (newTab) {
+      // Remote tab content does not focus synchronously, so we set the flag
+      // on this tab to skip focusing the content if we want to focus the URL
+      // bar instead.
+      newTab._urlbarFocused = true;
+    }
     w.focusAndSelectUrlBar();
+  }
 }
 
 // Used as an onclick handler for UI elements with link-like behavior.
 // e.g. onclick="checkForMiddleClick(this, event);"
 function checkForMiddleClick(node, event) {
   // We should be using the disabled property here instead of the attribute,
   // but some elements that this function is used with don't support it (e.g.
   // menuitem).
--- a/browser/components/loop/MozLoopAPI.jsm
+++ b/browser/components/loop/MozLoopAPI.jsm
@@ -156,16 +156,37 @@ function injectLoopAPI(targetWindow) {
       enumerable: true,
       writable: true,
       value: function(prefName) {
         return MozLoopService.getLoopCharPref(prefName);
       }
     },
 
     /**
+     * Return any preference under "loop." that's coercible to a boolean
+     * preference.
+     *
+     * @param {String} prefName The name of the pref without the preceding
+     * "loop."
+     *
+     * Any errors thrown by the Mozilla pref API are logged to the console
+     * and cause null to be returned. This includes the case of the preference
+     * not being found.
+     *
+     * @return {String} on success, null on error
+     */
+    getLoopBoolPref: {
+      enumerable: true,
+      writable: true,
+      value: function(prefName) {
+        return MozLoopService.getLoopBoolPref(prefName);
+      }
+    },
+
+    /**
      * Starts alerting the user about an incoming call
      */
     startAlerting: {
       enumerable: true,
       writable: true,
       value: function() {
         let chromeWindow = getChromeWindow(targetWindow);
         chromeWindow.getAttention();
--- a/browser/components/loop/MozLoopService.jsm
+++ b/browser/components/loop/MozLoopService.jsm
@@ -609,16 +609,39 @@ this.MozLoopService = {
     } catch (ex) {
       console.log("getLoopCharPref had trouble getting " + prefName +
         "; exception: " + ex);
       return null;
     }
   },
 
   /**
+   * Return any preference under "loop." that's coercible to a character
+   * preference.
+   *
+   * @param {String} prefName The name of the pref without the preceding
+   * "loop."
+   *
+   * Any errors thrown by the Mozilla pref API are logged to the console
+   * and cause null to be returned. This includes the case of the preference
+   * not being found.
+   *
+   * @return {String} on success, null on error
+   */
+  getLoopBoolPref: function(prefName) {
+    try {
+      return Services.prefs.getBoolPref("loop." + prefName);
+    } catch (ex) {
+      console.log("getLoopBoolPref had trouble getting " + prefName +
+        "; exception: " + ex);
+      return null;
+    }
+  },
+
+  /**
    * Performs a hawk based request to the loop server.
    *
    * @param {String} path The path to make the request to.
    * @param {String} method The request method, e.g. 'POST', 'GET'.
    * @param {Object} payloadObj An object which is converted to JSON and
    *                            transmitted with the request.
    * @returns {Promise}
    *        Returns a promise that resolves to the response of the API call,
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -27,34 +27,37 @@ loop.conversation = (function(OT, mozL10
       model: React.PropTypes.object.isRequired
     },
 
     getInitialState: function() {
       return {showDeclineMenu: false};
     },
 
     componentDidMount: function() {
-      window.addEventListener('click', this.clickHandler);
-      window.addEventListener('blur', this._hideDeclineMenu);
+      window.addEventListener("click", this.clickHandler);
+      window.addEventListener("blur", this._hideDeclineMenu);
     },
 
     componentWillUnmount: function() {
-      window.removeEventListener('click', this.clickHandler);
-      window.removeEventListener('blur', this._hideDeclineMenu);
+      window.removeEventListener("click", this.clickHandler);
+      window.removeEventListener("blur", this._hideDeclineMenu);
     },
 
     clickHandler: function(e) {
       var target = e.target;
       if (!target.classList.contains('btn-chevron')) {
         this._hideDeclineMenu();
       }
     },
 
-    _handleAccept: function() {
-      this.props.model.trigger("accept");
+    _handleAccept: function(callType) {
+      return () => {
+        this.props.model.set("selectedCallType", callType);
+        this.props.model.trigger("accept");
+      };
     },
 
     _handleDecline: function() {
       this.props.model.trigger("decline");
     },
 
     _handleDeclineBlock: function(e) {
       this.props.model.trigger("declineAndBlock");
@@ -69,50 +72,64 @@ loop.conversation = (function(OT, mozL10
     },
 
     _hideDeclineMenu: function() {
       this.setState({showDeclineMenu: false});
     },
 
     render: function() {
       /* jshint ignore:start */
-      var btnClassAccept = "btn btn-success btn-accept";
+      var btnClassAccept = "btn btn-success btn-accept call-audio-video";
       var btnClassBlock = "btn btn-error btn-block";
       var btnClassDecline = "btn btn-error btn-decline";
       var conversationPanelClass = "incoming-call " +
                                   loop.shared.utils.getTargetPlatform();
       var cx = React.addons.classSet;
-      var declineDropdownMenuClasses = cx({
+      var dropdownMenuClassesDecline = cx({
         "native-dropdown-menu": true,
-        "decline-block-menu": true,
+        "conversation-window-dropdown": true,
         "visually-hidden": !this.state.showDeclineMenu
       });
       return (
         React.DOM.div({className: conversationPanelClass}, 
           React.DOM.h2(null, __("incoming_call")), 
           React.DOM.div({className: "button-group incoming-call-action-group"}, 
             React.DOM.div({className: "button-chevron-menu-group"}, 
               React.DOM.div({className: "button-group-chevron"}, 
                 React.DOM.div({className: "button-group"}, 
-                  React.DOM.button({className: btnClassDecline, onClick: this._handleDecline}, 
+
+                  React.DOM.button({className: btnClassDecline, 
+                          onClick: this._handleDecline}, 
                     __("incoming_call_decline_button")
                   ), 
                   React.DOM.div({className: "btn-chevron", 
-                    onClick: this._toggleDeclineMenu}
+                       onClick: this._toggleDeclineMenu}
                   )
                 ), 
-                React.DOM.ul({className: declineDropdownMenuClasses}, 
+
+                React.DOM.ul({className: dropdownMenuClassesDecline}, 
                   React.DOM.li({className: "btn-block", onClick: this._handleDeclineBlock}, 
                     __("incoming_call_decline_and_block_button")
                   )
                 )
+
               )
             ), 
-            React.DOM.button({className: btnClassAccept, onClick: this._handleAccept}, 
-              __("incoming_call_answer_button")
+
+            React.DOM.div({className: "button-chevron-menu-group"}, 
+              React.DOM.div({className: "button-group"}, 
+                React.DOM.button({className: btnClassAccept, 
+                        onClick: this._handleAccept("audio-video")}, 
+                  __("incoming_call_answer_button")
+                ), 
+                React.DOM.div({className: "call-audio-only", 
+                     onClick: this._handleAccept("audio"), 
+                     title: __("incoming_call_answer_audio_only_tooltip")}
+                )
+              )
             )
           )
         )
       );
       /* jshint ignore:end */
     }
   });
 
@@ -176,19 +193,20 @@ loop.conversation = (function(OT, mozL10
           this._notifier.errorL10n("cannot_start_call_session_not_ready");
           return;
         }
         // XXX For incoming calls we might have more than one call queued.
         // For now, we'll just assume the first call is the right information.
         // We'll probably really want to be getting this data from the
         // background worker on the desktop client.
         // Bug 1032700 should fix this.
-        this._conversation.setSessionData(sessionData[0]);
+        this._conversation.setIncomingSessionData(sessionData[0]);
         this.loadReactComponent(loop.conversation.IncomingCallView({
-          model: this._conversation
+          model: this._conversation,
+          video: {enabled: this._conversation.hasVideoStream("incoming")}
         }));
       });
     },
 
     /**
      * Accepts an incoming call.
      */
     accept: function() {
@@ -208,17 +226,17 @@ loop.conversation = (function(OT, mozL10
     /**
      * Decline and block an incoming call
      * @note:
      * - loopToken is the callUrl identifier. It gets set in the panel
      *   after a callUrl is received
      */
     declineAndBlock: function() {
       navigator.mozLoop.stopAlerting();
-      var token = navigator.mozLoop.getLoopCharPref('loopToken');
+      var token = navigator.mozLoop.getLoopCharPref("loopToken");
       this._client.deleteCallUrl(token, function(error) {
         // XXX The conversation window will be closed when this cb is triggered
         // figure out if there is a better way to report the error to the user
         // (bug 1048909).
         console.log(error);
       });
       window.close();
     },
@@ -230,20 +248,24 @@ loop.conversation = (function(OT, mozL10
     conversation: function() {
       if (!this._conversation.isSessionReady()) {
         console.error("Error: navigated to conversation route without " +
           "the start route to initialise the call first");
         this._notifier.errorL10n("cannot_start_call_session_not_ready");
         return;
       }
 
+      var callType = this._conversation.get("selectedCallType");
+      var videoStream = callType === "audio" ? false : true;
+
       /*jshint newcap:false*/
       this.loadReactComponent(sharedViews.ConversationView({
         sdk: OT,
-        model: this._conversation
+        model: this._conversation,
+        video: {enabled: videoStream}
       }));
     },
 
     /**
      * Call has ended, display a feedback form.
      */
     feedback: function() {
       document.title = mozL10n.get("call_has_ended");
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -27,34 +27,37 @@ loop.conversation = (function(OT, mozL10
       model: React.PropTypes.object.isRequired
     },
 
     getInitialState: function() {
       return {showDeclineMenu: false};
     },
 
     componentDidMount: function() {
-      window.addEventListener('click', this.clickHandler);
-      window.addEventListener('blur', this._hideDeclineMenu);
+      window.addEventListener("click", this.clickHandler);
+      window.addEventListener("blur", this._hideDeclineMenu);
     },
 
     componentWillUnmount: function() {
-      window.removeEventListener('click', this.clickHandler);
-      window.removeEventListener('blur', this._hideDeclineMenu);
+      window.removeEventListener("click", this.clickHandler);
+      window.removeEventListener("blur", this._hideDeclineMenu);
     },
 
     clickHandler: function(e) {
       var target = e.target;
       if (!target.classList.contains('btn-chevron')) {
         this._hideDeclineMenu();
       }
     },
 
-    _handleAccept: function() {
-      this.props.model.trigger("accept");
+    _handleAccept: function(callType) {
+      return () => {
+        this.props.model.set("selectedCallType", callType);
+        this.props.model.trigger("accept");
+      };
     },
 
     _handleDecline: function() {
       this.props.model.trigger("decline");
     },
 
     _handleDeclineBlock: function(e) {
       this.props.model.trigger("declineAndBlock");
@@ -69,51 +72,65 @@ loop.conversation = (function(OT, mozL10
     },
 
     _hideDeclineMenu: function() {
       this.setState({showDeclineMenu: false});
     },
 
     render: function() {
       /* jshint ignore:start */
-      var btnClassAccept = "btn btn-success btn-accept";
+      var btnClassAccept = "btn btn-success btn-accept call-audio-video";
       var btnClassBlock = "btn btn-error btn-block";
       var btnClassDecline = "btn btn-error btn-decline";
       var conversationPanelClass = "incoming-call " +
                                   loop.shared.utils.getTargetPlatform();
       var cx = React.addons.classSet;
-      var declineDropdownMenuClasses = cx({
+      var dropdownMenuClassesDecline = cx({
         "native-dropdown-menu": true,
-        "decline-block-menu": true,
+        "conversation-window-dropdown": true,
         "visually-hidden": !this.state.showDeclineMenu
       });
       return (
         <div className={conversationPanelClass}>
           <h2>{__("incoming_call")}</h2>
           <div className="button-group incoming-call-action-group">
             <div className="button-chevron-menu-group">
               <div className="button-group-chevron">
                 <div className="button-group">
-                  <button className={btnClassDecline} onClick={this._handleDecline}>
+
+                  <button className={btnClassDecline}
+                          onClick={this._handleDecline}>
                     {__("incoming_call_decline_button")}
                   </button>
                   <div className="btn-chevron"
-                    onClick={this._toggleDeclineMenu}>
+                       onClick={this._toggleDeclineMenu}>
                   </div>
                 </div>
-                <ul className={declineDropdownMenuClasses}>
+
+                <ul className={dropdownMenuClassesDecline}>
                   <li className="btn-block" onClick={this._handleDeclineBlock}>
                     {__("incoming_call_decline_and_block_button")}
                   </li>
                 </ul>
+
               </div>
             </div>
-            <button className={btnClassAccept} onClick={this._handleAccept}>
-              {__("incoming_call_answer_button")}
-            </button>
+
+            <div className="button-chevron-menu-group">
+              <div className="button-group">
+                <button className={btnClassAccept}
+                        onClick={this._handleAccept("audio-video")}>
+                  {__("incoming_call_answer_button")}
+                </button>
+                <div className="call-audio-only"
+                     onClick={this._handleAccept("audio")}
+                     title={__("incoming_call_answer_audio_only_tooltip")} >
+                </div>
+              </div>
+            </div>
           </div>
         </div>
       );
       /* jshint ignore:end */
     }
   });
 
   /**
@@ -176,19 +193,20 @@ loop.conversation = (function(OT, mozL10
           this._notifier.errorL10n("cannot_start_call_session_not_ready");
           return;
         }
         // XXX For incoming calls we might have more than one call queued.
         // For now, we'll just assume the first call is the right information.
         // We'll probably really want to be getting this data from the
         // background worker on the desktop client.
         // Bug 1032700 should fix this.
-        this._conversation.setSessionData(sessionData[0]);
+        this._conversation.setIncomingSessionData(sessionData[0]);
         this.loadReactComponent(loop.conversation.IncomingCallView({
-          model: this._conversation
+          model: this._conversation,
+          video: {enabled: this._conversation.hasVideoStream("incoming")}
         }));
       });
     },
 
     /**
      * Accepts an incoming call.
      */
     accept: function() {
@@ -208,17 +226,17 @@ loop.conversation = (function(OT, mozL10
     /**
      * Decline and block an incoming call
      * @note:
      * - loopToken is the callUrl identifier. It gets set in the panel
      *   after a callUrl is received
      */
     declineAndBlock: function() {
       navigator.mozLoop.stopAlerting();
-      var token = navigator.mozLoop.getLoopCharPref('loopToken');
+      var token = navigator.mozLoop.getLoopCharPref("loopToken");
       this._client.deleteCallUrl(token, function(error) {
         // XXX The conversation window will be closed when this cb is triggered
         // figure out if there is a better way to report the error to the user
         // (bug 1048909).
         console.log(error);
       });
       window.close();
     },
@@ -230,20 +248,24 @@ loop.conversation = (function(OT, mozL10
     conversation: function() {
       if (!this._conversation.isSessionReady()) {
         console.error("Error: navigated to conversation route without " +
           "the start route to initialise the call first");
         this._notifier.errorL10n("cannot_start_call_session_not_ready");
         return;
       }
 
+      var callType = this._conversation.get("selectedCallType");
+      var videoStream = callType === "audio" ? false : true;
+
       /*jshint newcap:false*/
       this.loadReactComponent(sharedViews.ConversationView({
         sdk: OT,
-        model: this._conversation
+        model: this._conversation,
+        video: {enabled: videoStream}
       }));
     },
 
     /**
      * Call has ended, display a feedback form.
      */
     feedback: function() {
       document.title = mozL10n.get("call_has_ended");
--- a/browser/components/loop/content/shared/css/common.css
+++ b/browser/components/loop/content/shared/css/common.css
@@ -104,16 +104,21 @@ h1, h2, h3 {
 .btn-large {
   /* Dimensions from spec
    * https://people.mozilla.org/~dhenein/labs/loop-link-spec/#call-start */
   padding: .5em;
   font-size: 18px;
   height: auto;
 }
 
+  .btn-large + .btn-chevron {
+    padding: 1rem;
+    height: 100%; /* match full height of button */
+  }
+
 /*
  * Left / Right padding elements
  * used to center components
  * */
 .flex-padding-1 {
   display: flex;
   flex: 1;
 }
@@ -128,27 +133,30 @@ h1, h2, h3 {
     border: 1px solid #008acb;
   }
 
   .btn-info:active {
     background-color: #006b9d;
     border: 1px solid #006b9d;
   }
 
-.btn-success {
+.btn-success,
+.btn-success + .btn-chevron {
   background-color: #74bf43;
   border: 1px solid #74bf43;
 }
 
-  .btn-success:hover {
+  .btn-success:hover,
+  .btn-success + .btn-chevron:hover {
     background-color: #6cb23e;
     border: 1px solid #6cb23e;
   }
 
-  .btn-success:active {
+  .btn-success:active,
+  .btn-success + .btn-chevron:active {
     background-color: #64a43a;
     border: 1px solid #64a43a;
   }
 
 .btn-warning {
   background-color: #f0ad4e;
 }
 
@@ -229,16 +237,18 @@ h1, h2, h3 {
   display: flex;
   width: 100%;
   align-content: space-between;
   justify-content: center;
 }
 
 .button-group .btn {
   flex: 1;
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
 }
 
 /* Alerts */
 .alert {
   background: #eee;
   padding: .2em 1em;
   margin-bottom: 1em;
 }
@@ -287,34 +297,46 @@ h1, h2, h3 {
 }
 
 /* Transitions */
 .fade-out {
   transition: opacity 0.5s ease-in;
   opacity: 0;
 }
 
-.btn-large .icon {
-  display: inline-block;
-  width: 20px;
-  height: 20px;
+.icon,
+.icon-small,
+.icon-audio,
+.icon-video {
   background-size: 20px;
   background-repeat: no-repeat;
   vertical-align: top;
-  margin-left: 10px;
+  background-position: 80% center;
+}
+
+.icon-small {
+  background-size: 10px;
 }
 
 .icon-video {
   background-image: url("../img/video-inverse-14x14.png");
 }
 
+.icon-audio {
+  background-image: url("../img/audio-default-16x16@1.5x.png");
+}
+
 @media (min-resolution: 2dppx) {
   .icon-video {
     background-image: url("../img/video-inverse-14x14@2x.png");
   }
+
+  .icon-audio {
+    background-image: url("../img/audio-default-16x16@2x.png");
+  }
 }
 
 /*
  * Platform specific styles
  * The UI should match the user OS
  * Specific font sizes for text paragraphs to match
  * the interface on that platform.
  */
--- a/browser/components/loop/content/shared/css/conversation.css
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -189,16 +189,51 @@
   margin-left: .5em;
 }
 
 .incoming-call h2 {
   font-size: 1.5em;
   font-weight: normal;
 }
 
+.call-audio-only {
+  width: 26px;
+  height: 26px;
+  border-left: 1px solid rgba(255,255,255,.4);
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+  background-color: #74BF43;
+  background-image: url("../img/audio-inverse-14x14.png");
+  background-size: 1rem;
+  background-position: center;
+  background-repeat: no-repeat;
+  cursor: pointer;
+}
+
+  .call-audio-only:hover {
+    background-color: #6cb23e;
+  }
+
+
+.call-audio-video {
+  background-image: url("../img/video-inverse-14x14.png");
+  background-position: 96% center;
+  background-repeat: no-repeat;
+  background-size: 1rem;
+}
+
+@media (min-resolution: 2dppx) {
+  .call-audio-only {
+    background-image: url("../img/audio-inverse-14x14@2x.png");
+  }
+  .call-audio-video {
+    background-image: url("../img/video-inverse-14x14@2x.png");
+  }
+}
+
 /* Expired call url page */
 
 .expired-url-info {
   width: 400px;
   margin: 0 auto;
 }
 
 .promote-firefox {
@@ -207,43 +242,66 @@
   line-height: 24px;
   margin: 2em 0;
 }
 
 .promote-firefox h3 {
   font-weight: 300;
 }
 
-/* Block incoming call */
+/*
+ * Dropdown menu hidden behind a chevron
+ *
+ * .native-dropdown-menu[-large-parent] Generic class, contains common styles
+ * .standalone-dropdown-menu Initiate call dropdown menu
+ * .conversation-window-dropdown Dropdown menu for answer/decline/block options
+ */
 
-.native-dropdown-menu {
+.native-dropdown-menu,
+.native-dropdown-large-parent {
   /* Should match a native select menu */
   padding: 0;
   position: absolute; /* element can be wider than the parent */
   background: #fff;
   margin: 0;
   box-shadow: 0 4px 5px rgba(30, 30, 30, .3);
   border-style: solid;
   border-width: 1px 1px 1px 2px;
   border-color: #aaa #111 #111 #aaa;
 }
 
-.decline-block-menu li {
+  /*
+   * If the component is smaller than the parent
+   * we need it to display block to occupy full width
+   * Same as above but overrides apropriate styles
+   */
+  .native-dropdown-large-parent {
+    position: relative;
+    display: block;
+  }
+
+  .native-dropdown-menu li,
+  .native-dropdown-large-parent li {
+    list-style: none;
+    cursor: pointer;
+    color: #000;
+  }
+
+  .native-dropdown-menu li:hover,
+  .native-dropdown-large-parent li:hover,
+  .native-dropdown-large-parent li:hover button {
+    color: #fff;
+    background-color: #111;
+  }
+
+.conversation-window-dropdown li {
   padding: 0 10px 0 5px;
-  list-style: none;
   font-size: .9em;
-  color: #000;
-  cursor: pointer;
 }
 
-  .decline-block-menu li:hover {
-    color: #FFF;
-    background: #111;
-  }
-
 /* Expired call url page */
 
 .expired-url-info {
   width: 400px;
   margin: 0 auto;
 }
 
 .promote-firefox {
new file mode 100644
index 0000000000000000000000000000000000000000..fdef44157a2a18c0362e1219341de82a3ffdc12f
GIT binary patch
literal 424
zc$@*K0ayNsP)<h;3K|Lk000e1NJLTq000;O000;W1ONa4N`Cco0004RNkl<Zcmd7S
zv1=4T0EO}IjdKtKiU>lmNh61Xuwtw%6l0S@1w{$QG9X%sg;)uKofcxJe}SMy8Y{s@
z!A8O4MB$292o@58#3Gv8)n~EGF|&6~I)7jDn(1anjF>+YZmRGm@3~8l7G0+0zHZTQ
zr3Ido(E=&Y>J_P<?(&^PFln44w_B$~S`?W>v>hZ9$yg$1k%?w|0{`y;Ut^g$#?Wn+
zecaSVQwviR>@j2PSD{@rVqkkB4VU6?M<p#T-3hoHy&8Q`!3u3X6;Smn>OwQ{2hi#2
znFpl4($i6|#cz?iFdVC1;z*qHb#Kw|+MjtnVuA-_-^14QM9-7ltCr#-1)F+TK8<&D
zg^&FiN*bDhp#z6^ykOd^eyJ5ts^F~l^7_{W))~@yQgL6r!J?+9efHz(2?G+kMBA56
zcSAeDZ#cn-7-{R4GJpn*5k%HiebNsm0esTye(PD2l>Zt&riZlXcX^QwhW-JB9goF0
S*`kL40000<MNUMnLSTY#O}w)J
new file mode 100644
index 0000000000000000000000000000000000000000..71ed8d8e3bf9df9217455979547bfbf64bf274b8
GIT binary patch
literal 536
zc$@(k0_XjSP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80005sNkl<ZSi@sr
zAQ6OyhVn;7Mz#R){-~&^cR>6Q$le$c5s?IxW@Mlx09xV=wCp+1(*M{nQ0^E|jRH+9
z4-XI51X}VHm*q(K3^0_~sO|uu?@kk8IT!;&p`NOi0}WLr)^cc6+@iMcJxFxGZ)zt#
zKT;e3!a!|IqYfB#z^DT#wKN-w4as!?P+uU(3}7+tLr&=jD^$wJbpTNBA*dN!MjbHp
z901hx4XU{j=m2LDE2D2vPn?B{ts=((cc7Y=0vi|-K>9BUjyMGh0cevA<e&-UIAAW+
zu=frQ4je%KN)j3*vB;qY%8ule0}e=r)&j90r~yhu@Gk>3PJ!&>Q2r}lUtcbA8zQ@4
z4Gdsm;t6Cc0r5^;jSwL20$B#6`;p}G$u13naW4&P1q10nK->!y<AJu2nnBHRAYKB*
zr9g2lXwz*ElB2d#+*Aifg)GpZi%5n(0!2w!SeP9!RFpv$gNj<9x@kbUA4uxv8XFt4
zQl&D2`WocZKSU(L_dv%K(xh(yiV{$h8<eoHSbQERmjG15$v|rWv}_KRL>Rz8FEAhu
z00ylt(2{DPWmACkH7rrE4OHR*>72m8Kw)ZkOe#sN3qAm`4OJ`$`bG?B=vttG>qx{z
amHz-e&RiG!)_<%30000<MNUMnLSTZtwbGCP
--- a/browser/components/loop/content/shared/js/models.js
+++ b/browser/components/loop/content/shared/js/models.js
@@ -9,27 +9,31 @@ loop.shared = loop.shared || {};
 loop.shared.models = (function() {
   "use strict";
 
   /**
    * Conversation model.
    */
   var ConversationModel = Backbone.Model.extend({
     defaults: {
-      connected:    false,     // Session connected flag
-      ongoing:      false,     // Ongoing call flag
-      callerId:     undefined, // Loop caller id
-      loopToken:    undefined, // Loop conversation token
-      loopVersion:  undefined, // Loop version for /calls/ information. This
-                               // is the version received from the push
-                               // notification and is used by the server to
-                               // determine the pending calls
-      sessionId:    undefined, // OT session id
-      sessionToken: undefined, // OT session token
-      apiKey:       undefined  // OT api key
+      connected:    false,         // Session connected flag
+      ongoing:      false,         // Ongoing call flag
+      callerId:     undefined,     // Loop caller id
+      loopToken:    undefined,     // Loop conversation token
+      loopVersion:  undefined,     // Loop version for /calls/ information. This
+                                   // is the version received from the push
+                                   // notification and is used by the server to
+                                   // determine the pending calls
+      sessionId:    undefined,     // OT session id
+      sessionToken: undefined,     // OT session token
+      apiKey:       undefined,     // OT api key
+      callType:     undefined,     // The type of incoming call selected by
+                                   // other peer ("audio" or "audio-video")
+      selectedCallType: undefined  // The selected type for the call that was
+                                   // initiated ("audio" or "audio-video")
     },
 
     /**
      * SDK object.
      * @type {OT}
      */
     sdk: undefined,
 
@@ -109,44 +113,60 @@ loop.shared.models = (function() {
           this.trigger("timeout").endSession();
         }
       }
 
       // Setup pending call timeout.
       this._pendingCallTimer = setTimeout(
         handleOutgoingCallTimeout.bind(this), this.pendingCallTimeout);
 
-      this.setSessionData(sessionData);
+      this.setOutgoingSessionData(sessionData);
       this.trigger("call:outgoing");
     },
 
     /**
      * Checks that the session is ready.
      *
      * @return {Boolean}
      */
     isSessionReady: function() {
       return !!this.get("sessionId");
     },
 
     /**
      * Sets session information.
+     * Session data received by creating an outgoing call.
      *
      * @param {Object} sessionData Conversation session information.
      */
-    setSessionData: function(sessionData) {
+    setOutgoingSessionData: function(sessionData) {
       // Explicit property assignment to prevent later "surprises"
       this.set({
         sessionId:    sessionData.sessionId,
         sessionToken: sessionData.sessionToken,
         apiKey:       sessionData.apiKey
       });
     },
 
     /**
+     * Sets session information about the incoming call.
+     *
+     * @param {Object} sessionData Conversation session information.
+     */
+    setIncomingSessionData: function(sessionData) {
+      // Explicit property assignment to prevent later "surprises"
+      this.set({
+        sessionId:    sessionData.sessionId,
+        sessionToken: sessionData.sessionToken,
+        apiKey:       sessionData.apiKey,
+        callType:     sessionData.callType || "audio-video"
+      });
+    },
+
+    /**
      * Starts a SDK session and subscribe to call events.
      */
     startSession: function() {
       if (!this.isSessionReady()) {
         throw new Error("Can't start session as it's not ready");
       }
       this.session = this.sdk.initSession(this.get("sessionId"));
       this.listenTo(this.session, "streamCreated", this._streamCreated);
@@ -165,16 +185,32 @@ loop.shared.models = (function() {
      */
     endSession: function() {
       this.session.disconnect();
       this.set("ongoing", false)
           .once("session:ended", this.stopListening, this);
     },
 
     /**
+     * Helper function to determine if video stream is available for the
+     * incoming or outgoing call
+     *
+     * @param {string} callType Incoming or outgoing call
+     */
+    hasVideoStream: function(callType) {
+      if (callType === "incoming") {
+        return this.get("callType") === "audio-video";
+      }
+      if (callType === "outgoing") {
+        return this.get("selectedCallType") === "audio-video";
+      }
+      return undefined;
+    },
+
+    /**
      * Handle a loop-server error, which has an optional `errno` property which
      * is server error identifier.
      *
      * Triggers the following events:
      *
      * - `session:expired` for expired call urls
      * - `session:error` for other generic errors
      *
--- a/browser/components/loop/content/shared/js/views.js
+++ b/browser/components/loop/content/shared/js/views.js
@@ -212,23 +212,34 @@ loop.shared.views = (function(_, OT, l10
       height: "100%",
       style: {
         bugDisplayMode: "off",
         buttonDisplayMode: "off",
         nameDisplayMode: "off"
       }
     },
 
+    getInitialProps: function() {
+      return {
+        video: {enabled: true},
+        audio: {enabled: true}
+      };
+    },
+
     getInitialState: function() {
       return {
-        video: {enabled: false},
-        audio: {enabled: false}
+        video: this.props.video,
+        audio: this.props.audio
       };
     },
 
+    componentWillMount: function() {
+      this.publisherConfig.publishVideo = this.props.video.enabled;
+    },
+
     componentDidMount: function() {
       this.listenTo(this.props.model, "session:connected",
                                       this.startPublishing);
       this.listenTo(this.props.model, "session:stream-created",
                                       this._streamCreated);
       this.listenTo(this.props.model, ["session:peer-hungup",
                                        "session:network-disconnected",
                                        "session:ended"].join(" "),
--- a/browser/components/loop/content/shared/js/views.jsx
+++ b/browser/components/loop/content/shared/js/views.jsx
@@ -212,23 +212,34 @@ loop.shared.views = (function(_, OT, l10
       height: "100%",
       style: {
         bugDisplayMode: "off",
         buttonDisplayMode: "off",
         nameDisplayMode: "off"
       }
     },
 
+    getInitialProps: function() {
+      return {
+        video: {enabled: true},
+        audio: {enabled: true}
+      };
+    },
+
     getInitialState: function() {
       return {
-        video: {enabled: false},
-        audio: {enabled: false}
+        video: this.props.video,
+        audio: this.props.audio
       };
     },
 
+    componentWillMount: function() {
+      this.publisherConfig.publishVideo = this.props.video.enabled;
+    },
+
     componentDidMount: function() {
       this.listenTo(this.props.model, "session:connected",
                                       this.startPublishing);
       this.listenTo(this.props.model, "session:stream-created",
                                       this._streamCreated);
       this.listenTo(this.props.model, ["session:peer-hungup",
                                        "session:network-disconnected",
                                        "session:ended"].join(" "),
--- a/browser/components/loop/standalone/content/css/webapp.css
+++ b/browser/components/loop/standalone/content/css/webapp.css
@@ -119,8 +119,44 @@ header {
   font-weight: lighter;
 }
 
 .light-color-font {
   opacity: .4;
   font-weight: normal;
 }
 
+.start-audio-only-call,
+.start-audio-video-call {
+  background-color: none;
+  background-image: url("../shared/img/audio-default-16x16@1.5x.png");
+  background-position: 80% center;
+  background-size: 10px;
+  background-repeat: no-repeat;
+  cursor: pointer;
+}
+
+.start-audio-only-call {
+  border: none;
+  width: 100%;
+}
+
+.start-audio-only-call:hover {
+  background-image: url("../shared/img/audio-inverse-14x14.png");
+}
+
+.start-audio-video-call {
+  background-size: 20px;
+  background-image: url("../shared/img/video-inverse-14x14.png");
+}
+
+@media (min-resolution: 2dppx) {
+  .start-audio-only-call {
+    background-image: url("../shared/img/audio-default-16x16@2x.png");
+  }
+  .start-audio-only-call:hover {
+    background-image: url("../shared/img/audio-inverse-14x14@2x.png");
+  }
+  .start-audio-video-call {
+    background-image: url("../shared/img/video-inverse-14x14@2x.png");
+  }
+}
+
--- a/browser/components/loop/standalone/content/js/webapp.js
+++ b/browser/components/loop/standalone/content/js/webapp.js
@@ -139,76 +139,109 @@ loop.webapp = (function($, _, OT, webL10
      * - {loop.shared.model.ConversationModel}    model    Conversation model.
      * - {loop.shared.views.NotificationListView} notifier Notifier component.
      *
      */
 
     getInitialState: function() {
       return {
         urlCreationDateString: '',
-        disableCallButton: false
+        disableCallButton: false,
+        showCallOptionsMenu: false
       };
     },
 
     propTypes: {
       model: React.PropTypes.instanceOf(sharedModels.ConversationModel)
                                        .isRequired,
       // XXX Check more tightly here when we start injecting window.loop.*
       notifier: React.PropTypes.object.isRequired,
       client: React.PropTypes.object.isRequired
     },
 
     componentDidMount: function() {
+      // Listen for events & hide dropdown menu if user clicks away
+      window.addEventListener("click", this.clickHandler);
       this.props.model.listenTo(this.props.model, "session:error",
                                 this._onSessionError);
       this.props.client.requestCallUrlInfo(this.props.model.get("loopToken"),
                                            this._setConversationTimestamp);
       // XXX DOM element does not exist before React view gets instantiated
       // We should turn the notifier into a react component
       this.props.notifier.$el = $("#messages");
     },
 
     _onSessionError: function(error) {
       console.error(error);
       this.props.notifier.errorL10n("unable_retrieve_call_info");
     },
 
     /**
      * Initiates the call.
+     * Takes in a call type parameter "audio" or "audio-video" and returns
+     * a function that initiates the call. React click handler requires a function
+     * to be called when that event happenes.
+     *
+     * @param {string} User call type choice "audio" or "audio-video"
      */
-    _initiateOutgoingCall: function() {
-      this.setState({disableCallButton: true});
-      this.props.model.setupOutgoingCall();
+    _initiateOutgoingCall: function(callType) {
+      return function() {
+        this.props.model.set("selectedCallType", callType);
+        this.setState({disableCallButton: true});
+        this.props.model.setupOutgoingCall();
+      }.bind(this);
     },
 
     _setConversationTimestamp: function(err, callUrlInfo) {
       if (err) {
         this.props.notifier.errorL10n("unable_retrieve_call_info");
       } else {
         var date = (new Date(callUrlInfo.urlCreationDate * 1000));
         var options = {year: "numeric", month: "long", day: "numeric"};
         var timestamp = date.toLocaleDateString(navigator.language, options);
 
         this.setState({urlCreationDateString: timestamp});
       }
     },
 
+    componentWillUnmount: function() {
+      window.removeEventListener("click", this.clickHandler);
+    },
+
+    clickHandler: function(e) {
+      if (!e.target.classList.contains('btn-chevron') &&
+          this.state.showCallOptionsMenu) {
+            this._toggleCallOptionsMenu();
+      }
+    },
+
+    _toggleCallOptionsMenu: function() {
+      var state = this.state.showCallOptionsMenu;
+      this.setState({showCallOptionsMenu: !state});
+    },
+
     render: function() {
       var tos_link_name = __("terms_of_use_link_text");
       var privacy_notice_name = __("privacy_notice_link_text");
 
       var tosHTML = __("legal_text_and_links", {
         "terms_of_use_url": "<a target=_blank href='" +
           "https://accounts.firefox.com/legal/terms'>" + tos_link_name + "</a>",
         "privacy_notice_url": "<a target=_blank href='" +
           "https://www.mozilla.org/privacy/'>" + privacy_notice_name + "</a>"
       });
 
-      var callButtonClasses = "btn btn-success btn-large " +
+      var btnClassStartCall = "btn btn-large btn-success " +
+                              "start-audio-video-call " +
                               loop.shared.utils.getTargetPlatform();
+      var dropdownMenuClasses = React.addons.classSet({
+        "native-dropdown-large-parent": true,
+        "standalone-dropdown-menu": true,
+        "visually-hidden": !this.state.showCallOptionsMenu
+      });
 
       return (
         /* jshint ignore:start */
         React.DOM.div({className: "container"}, 
           React.DOM.div({className: "container-box"}, 
 
             ConversationHeader({
               urlCreationDateString: this.state.urlCreationDateString}), 
@@ -216,21 +249,47 @@ loop.webapp = (function($, _, OT, webL10
             React.DOM.p({className: "large-font light-weight-font"}, 
               __("initiate_call_button_label")
             ), 
 
             React.DOM.div({id: "messages"}), 
 
             React.DOM.div({className: "button-group"}, 
               React.DOM.div({className: "flex-padding-1"}), 
-              React.DOM.button({ref: "submitButton", onClick: this._initiateOutgoingCall, 
-                className: callButtonClasses, 
-                disabled: this.state.disableCallButton}, 
-                __("initiate_call_button"), 
-                React.DOM.i({className: "icon icon-video"})
+              React.DOM.div({className: "button-chevron-menu-group"}, 
+                React.DOM.div({className: "button-group-chevron"}, 
+                  React.DOM.div({className: "button-group"}, 
+
+                    React.DOM.button({className: btnClassStartCall, 
+                            onClick: this._initiateOutgoingCall("audio-video"), 
+                            disabled: this.state.disableCallButton, 
+                            title: __("initiate_audio_video_call_tooltip")}, 
+                      __("initiate_audio_video_call_button")
+                    ), 
+
+                    React.DOM.div({className: "btn-chevron", 
+                      onClick: this._toggleCallOptionsMenu}
+                    )
+
+                  ), 
+
+                  React.DOM.ul({className: dropdownMenuClasses}, 
+                    React.DOM.li(null, 
+                      /*
+                       Button required for disabled state.
+                       */
+                      React.DOM.button({className: "start-audio-only-call", 
+                              onClick: this._initiateOutgoingCall("audio"), 
+                              disabled: this.state.disableCallButton}, 
+                        __("initiate_audio_call_button")
+                      )
+                    )
+                  )
+
+                )
               ), 
               React.DOM.div({className: "flex-padding-1"})
             ), 
 
             React.DOM.p({className: "terms-service", 
                dangerouslySetInnerHTML: {__html: tosHTML}})
           ), 
 
@@ -275,22 +334,22 @@ loop.webapp = (function($, _, OT, webL10
      * server.
      */
     setupOutgoingCall: function() {
       var loopToken = this._conversation.get("loopToken");
       if (!loopToken) {
         this._notifier.errorL10n("missing_conversation_info");
         this.navigate("home", {trigger: true});
       } else {
+        var callType = this._conversation.get("selectedCallType");
+
         this._conversation.once("call:outgoing", this.startCall, this);
 
-        // XXX For now, we assume both audio and video as there is no
-        // other option to select (bug 1048333)
-        this._client.requestCallInfo(this._conversation.get("loopToken"), "audio-video",
-                                     function(err, sessionData) {
+        this._client.requestCallInfo(this._conversation.get("loopToken"),
+                                     callType, function(err, sessionData) {
           if (err) {
             switch (err.errno) {
               // loop-server sends 404 + INVALID_TOKEN (errno 105) whenever a token is
               // missing OR expired; we treat this information as if the url is always
               // expired.
               case 105:
                 this._onSessionExpired();
                 break;
@@ -384,17 +443,18 @@ loop.webapp = (function($, _, OT, webL10
      */
     loadConversation: function(loopToken) {
       if (!this._conversation.isSessionReady()) {
         // User has loaded this url directly, actually setup the call.
         return this.navigate("call/" + loopToken, {trigger: true});
       }
       this.loadReactComponent(sharedViews.ConversationView({
         sdk: OT,
-        model: this._conversation
+        model: this._conversation,
+        video: {enabled: this._conversation.hasVideoStream("outgoing")}
       }));
     }
   });
 
   /**
    * Local helpers.
    */
   function WebappHelper() {
--- a/browser/components/loop/standalone/content/js/webapp.jsx
+++ b/browser/components/loop/standalone/content/js/webapp.jsx
@@ -139,76 +139,109 @@ loop.webapp = (function($, _, OT, webL10
      * - {loop.shared.model.ConversationModel}    model    Conversation model.
      * - {loop.shared.views.NotificationListView} notifier Notifier component.
      *
      */
 
     getInitialState: function() {
       return {
         urlCreationDateString: '',
-        disableCallButton: false
+        disableCallButton: false,
+        showCallOptionsMenu: false
       };
     },
 
     propTypes: {
       model: React.PropTypes.instanceOf(sharedModels.ConversationModel)
                                        .isRequired,
       // XXX Check more tightly here when we start injecting window.loop.*
       notifier: React.PropTypes.object.isRequired,
       client: React.PropTypes.object.isRequired
     },
 
     componentDidMount: function() {
+      // Listen for events & hide dropdown menu if user clicks away
+      window.addEventListener("click", this.clickHandler);
       this.props.model.listenTo(this.props.model, "session:error",
                                 this._onSessionError);
       this.props.client.requestCallUrlInfo(this.props.model.get("loopToken"),
                                            this._setConversationTimestamp);
       // XXX DOM element does not exist before React view gets instantiated
       // We should turn the notifier into a react component
       this.props.notifier.$el = $("#messages");
     },
 
     _onSessionError: function(error) {
       console.error(error);
       this.props.notifier.errorL10n("unable_retrieve_call_info");
     },
 
     /**
      * Initiates the call.
+     * Takes in a call type parameter "audio" or "audio-video" and returns
+     * a function that initiates the call. React click handler requires a function
+     * to be called when that event happenes.
+     *
+     * @param {string} User call type choice "audio" or "audio-video"
      */
-    _initiateOutgoingCall: function() {
-      this.setState({disableCallButton: true});
-      this.props.model.setupOutgoingCall();
+    _initiateOutgoingCall: function(callType) {
+      return function() {
+        this.props.model.set("selectedCallType", callType);
+        this.setState({disableCallButton: true});
+        this.props.model.setupOutgoingCall();
+      }.bind(this);
     },
 
     _setConversationTimestamp: function(err, callUrlInfo) {
       if (err) {
         this.props.notifier.errorL10n("unable_retrieve_call_info");
       } else {
         var date = (new Date(callUrlInfo.urlCreationDate * 1000));
         var options = {year: "numeric", month: "long", day: "numeric"};
         var timestamp = date.toLocaleDateString(navigator.language, options);
 
         this.setState({urlCreationDateString: timestamp});
       }
     },
 
+    componentWillUnmount: function() {
+      window.removeEventListener("click", this.clickHandler);
+    },
+
+    clickHandler: function(e) {
+      if (!e.target.classList.contains('btn-chevron') &&
+          this.state.showCallOptionsMenu) {
+            this._toggleCallOptionsMenu();
+      }
+    },
+
+    _toggleCallOptionsMenu: function() {
+      var state = this.state.showCallOptionsMenu;
+      this.setState({showCallOptionsMenu: !state});
+    },
+
     render: function() {
       var tos_link_name = __("terms_of_use_link_text");
       var privacy_notice_name = __("privacy_notice_link_text");
 
       var tosHTML = __("legal_text_and_links", {
         "terms_of_use_url": "<a target=_blank href='" +
           "https://accounts.firefox.com/legal/terms'>" + tos_link_name + "</a>",
         "privacy_notice_url": "<a target=_blank href='" +
           "https://www.mozilla.org/privacy/'>" + privacy_notice_name + "</a>"
       });
 
-      var callButtonClasses = "btn btn-success btn-large " +
+      var btnClassStartCall = "btn btn-large btn-success " +
+                              "start-audio-video-call " +
                               loop.shared.utils.getTargetPlatform();
+      var dropdownMenuClasses = React.addons.classSet({
+        "native-dropdown-large-parent": true,
+        "standalone-dropdown-menu": true,
+        "visually-hidden": !this.state.showCallOptionsMenu
+      });
 
       return (
         /* jshint ignore:start */
         <div className="container">
           <div className="container-box">
 
             <ConversationHeader
               urlCreationDateString={this.state.urlCreationDateString} />
@@ -216,22 +249,48 @@ loop.webapp = (function($, _, OT, webL10
             <p className="large-font light-weight-font">
               {__("initiate_call_button_label")}
             </p>
 
             <div id="messages"></div>
 
             <div className="button-group">
               <div className="flex-padding-1"></div>
-              <button ref="submitButton" onClick={this._initiateOutgoingCall}
-                className={callButtonClasses}
-                disabled={this.state.disableCallButton}>
-                {__("initiate_call_button")}
-                <i className="icon icon-video"></i>
-              </button>
+              <div className="button-chevron-menu-group">
+                <div className="button-group-chevron">
+                  <div className="button-group">
+
+                    <button className={btnClassStartCall}
+                            onClick={this._initiateOutgoingCall("audio-video")}
+                            disabled={this.state.disableCallButton}
+                            title={__("initiate_audio_video_call_tooltip")} >
+                      {__("initiate_audio_video_call_button")}
+                    </button>
+
+                    <div className="btn-chevron"
+                      onClick={this._toggleCallOptionsMenu}>
+                    </div>
+
+                  </div>
+
+                  <ul className={dropdownMenuClasses}>
+                    <li>
+                      {/*
+                       Button required for disabled state.
+                       */}
+                      <button className="start-audio-only-call"
+                              onClick={this._initiateOutgoingCall("audio")}
+                              disabled={this.state.disableCallButton} >
+                        {__("initiate_audio_call_button")}
+                      </button>
+                    </li>
+                  </ul>
+
+                </div>
+              </div>
               <div className="flex-padding-1"></div>
             </div>
 
             <p className="terms-service"
                dangerouslySetInnerHTML={{__html: tosHTML}}></p>
           </div>
 
           <ConversationFooter />
@@ -275,22 +334,22 @@ loop.webapp = (function($, _, OT, webL10
      * server.
      */
     setupOutgoingCall: function() {
       var loopToken = this._conversation.get("loopToken");
       if (!loopToken) {
         this._notifier.errorL10n("missing_conversation_info");
         this.navigate("home", {trigger: true});
       } else {
+        var callType = this._conversation.get("selectedCallType");
+
         this._conversation.once("call:outgoing", this.startCall, this);
 
-        // XXX For now, we assume both audio and video as there is no
-        // other option to select (bug 1048333)
-        this._client.requestCallInfo(this._conversation.get("loopToken"), "audio-video",
-                                     function(err, sessionData) {
+        this._client.requestCallInfo(this._conversation.get("loopToken"),
+                                     callType, function(err, sessionData) {
           if (err) {
             switch (err.errno) {
               // loop-server sends 404 + INVALID_TOKEN (errno 105) whenever a token is
               // missing OR expired; we treat this information as if the url is always
               // expired.
               case 105:
                 this._onSessionExpired();
                 break;
@@ -384,17 +443,18 @@ loop.webapp = (function($, _, OT, webL10
      */
     loadConversation: function(loopToken) {
       if (!this._conversation.isSessionReady()) {
         // User has loaded this url directly, actually setup the call.
         return this.navigate("call/" + loopToken, {trigger: true});
       }
       this.loadReactComponent(sharedViews.ConversationView({
         sdk: OT,
-        model: this._conversation
+        model: this._conversation,
+        video: {enabled: this._conversation.hasVideoStream("outgoing")}
       }));
     }
   });
 
   /**
    * Local helpers.
    */
   function WebappHelper() {
--- a/browser/components/loop/standalone/content/l10n/data.ini
+++ b/browser/components/loop/standalone/content/l10n/data.ini
@@ -20,17 +20,19 @@ sorry_device_unsupported=Sorry, Loop doe
 use_firefox_windows_mac_linux=Please open this page using the latest Firefox on Windows, Android, Mac or Linux.
 connection_error_see_console_notification=Call failed; see console for details.
 call_url_unavailable_notification_heading=Oops!
 call_url_unavailable_notification_message=This URL is unavailable.
 promote_firefox_hello_heading=Download Firefox to make free audio and video calls!
 get_firefox_button=Get Firefox
 call_url_unavailable_notification=This URL is unavailable.
 initiate_call_button_label=Click Call to start a video chat
-initiate_call_button=Call
+initiate_audio_video_call_button=Call
+initiate_audio_video_call_tooltip=Start a video call
+initiate_audio_call_button=Voice call
 ## LOCALIZATION NOTE (legal_text_and_links): In this item, don't translate the
 ## part between {{..}}
 legal_text_and_links=By using this product you agree to the {{terms_of_use_url}} and {{privacy_notice_url}}
 terms_of_use_link_text=Terms of use
 privacy_notice_link_text=Privacy notice
 brandShortname=Firefox
 clientShortname=WebRTC!
 ## LOCALIZATION NOTE (call_url_creation_date_label): Example output: (from May 26, 2014)
--- a/browser/components/loop/test/desktop-local/conversation_test.js
+++ b/browser/components/loop/test/desktop-local/conversation_test.js
@@ -114,17 +114,18 @@ describe("loop.conversation", function()
 
     beforeEach(function() {
       client = new loop.Client();
       conversation = new loop.shared.models.ConversationModel({}, {
         sdk: {},
         pendingCallTimeout: 1000,
       });
       sandbox.stub(client, "requestCallsInfo");
-      sandbox.stub(conversation, "setSessionData");
+      sandbox.stub(conversation, "setIncomingSessionData");
+      sandbox.stub(conversation, "setOutgoingSessionData");
     });
 
     describe("Routes", function() {
       var router;
 
       beforeEach(function() {
         router = new ConversationRouter({
           client: client,
@@ -187,36 +188,51 @@ describe("loop.conversation", function()
 
         describe("requestCallsInfo successful", function() {
           var fakeSessionData;
 
           beforeEach(function() {
             fakeSessionData  = {
               sessionId:    "sessionId",
               sessionToken: "sessionToken",
-              apiKey:       "apiKey"
+              apiKey:       "apiKey",
+              callType:     "callType"
             };
 
             client.requestCallsInfo.callsArgWith(1, null, [fakeSessionData]);
           });
 
           it("should store the session data", function() {
             router.incoming(42);
 
-            sinon.assert.calledOnce(conversation.setSessionData);
-            sinon.assert.calledWithExactly(conversation.setSessionData,
+            sinon.assert.calledOnce(conversation.setIncomingSessionData);
+            sinon.assert.calledWithExactly(conversation.setIncomingSessionData,
                                            fakeSessionData);
           });
 
+          it("should call the view with video.enabled=false", function() {
+            sandbox.stub(conversation, "get").withArgs("callType").returns("audio");
+            router.incoming("fakeVersion");
+
+            sinon.assert.calledOnce(conversation.get);
+            sinon.assert.calledOnce(loop.conversation.IncomingCallView);
+            sinon.assert.calledWithExactly(loop.conversation.IncomingCallView,
+                                           {model: conversation,
+                                           video: {enabled: false}});
+          });
+
           it("should display the incoming call view", function() {
+            sandbox.stub(conversation, "get").withArgs("callType")
+                                                      .returns("audio-video");
             router.incoming("fakeVersion");
 
             sinon.assert.calledOnce(loop.conversation.IncomingCallView);
             sinon.assert.calledWithExactly(loop.conversation.IncomingCallView,
-                                           {model: conversation});
+                                           {model: conversation,
+                                           video: {enabled: true}});
             sinon.assert.calledOnce(router.loadReactComponent);
             sinon.assert.calledWith(router.loadReactComponent,
               sinon.match(function(value) {
                 return TestUtils.isDescriptorOfType(value,
                   loop.conversation.IncomingCallView);
               }));
           });
         });
@@ -434,19 +450,42 @@ describe("loop.conversation", function()
     });
 
     describe("click event on .btn-accept", function() {
       it("should trigger an 'accept' conversation model event", function() {
         var buttonAccept = view.getDOMNode().querySelector(".btn-accept");
 
         TestUtils.Simulate.click(buttonAccept);
 
-        sinon.assert.calledOnce(model.trigger);
+        /* Setting a model property triggers 2 events */
+        sinon.assert.calledThrice(model.trigger);
         sinon.assert.calledWith(model.trigger, "accept");
-        });
+        sinon.assert.calledWith(model.trigger, "change:selectedCallType");
+        sinon.assert.calledWith(model.trigger, "change");
+      });
+
+      it("should set selectedCallType to audio-video", function() {
+        var buttonAccept = view.getDOMNode().querySelector(".call-audio-video");
+        sandbox.stub(model, "set");
+
+        TestUtils.Simulate.click(buttonAccept);
+
+        sinon.assert.calledOnce(model.set);
+        sinon.assert.calledWithExactly(model.set, "selectedCallType", "audio-video");
+      });
+
+      it("should set selectedCallType to audio", function() {
+        var buttonAccept = view.getDOMNode().querySelector(".call-audio-only");
+        sandbox.stub(model, "set");
+
+        TestUtils.Simulate.click(buttonAccept);
+
+        sinon.assert.calledOnce(model.set);
+        sinon.assert.calledWithExactly(model.set, "selectedCallType", "audio");
+      });
     });
 
     describe("click event on .btn-decline", function() {
       it("should trigger an 'decline' conversation model event", function() {
         var buttonDecline = view.getDOMNode().querySelector(".btn-decline");
 
         TestUtils.Simulate.click(buttonDecline);
 
--- a/browser/components/loop/test/mochitest/browser.ini
+++ b/browser/components/loop/test/mochitest/browser.ini
@@ -1,8 +1,8 @@
 [DEFAULT]
 support-files =
     head.js
 
 [browser_mozLoop_appVersionInfo.js]
-[browser_mozLoop_charPref.js]
+[browser_mozLoop_prefs.js]
 [browser_mozLoop_doNotDisturb.js]
 skip-if = buildapp == 'mulet'
rename from browser/components/loop/test/mochitest/browser_mozLoop_charPref.js
rename to browser/components/loop/test/mochitest/browser_mozLoop_prefs.js
--- a/browser/components/loop/test/mochitest/browser_mozLoop_charPref.js
+++ b/browser/components/loop/test/mochitest/browser_mozLoop_prefs.js
@@ -19,8 +19,22 @@ add_task(function* test_mozLoop_charPref
   gMozLoopAPI.setLoopCharPref("test", "foo");
   Assert.equal(Services.prefs.getCharPref("loop.test"), "foo",
                "should set loop pref value correctly");
 
   // Test getLoopCharPref
   Assert.equal(gMozLoopAPI.getLoopCharPref("test"), "foo",
                "should get loop pref value correctly");
 });
+
+add_task(function* test_mozLoop_boolPref() {
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("loop.testBool");
+  });
+
+  Assert.ok(gMozLoopAPI, "mozLoop should exist");
+
+  Services.prefs.setBoolPref("loop.testBool", true);
+
+  // Test getLoopCharPref
+  Assert.equal(gMozLoopAPI.getLoopBoolPref("testBool"), true,
+               "should get loop pref value correctly");
+});
--- a/browser/components/loop/test/shared/models_test.js
+++ b/browser/components/loop/test/shared/models_test.js
@@ -19,17 +19,18 @@ describe("loop.shared.models", function(
     requests = [];
     // https://github.com/cjohansen/Sinon.JS/issues/393
     fakeXHR.xhr.onCreate = function(xhr) {
       requests.push(xhr);
     };
     fakeSessionData = {
       sessionId:    "sessionId",
       sessionToken: "sessionToken",
-      apiKey:       "apiKey"
+      apiKey:       "apiKey",
+      callType:     "callType"
     };
     fakeSession = _.extend({
       connect: function () {},
       endSession: sandbox.stub(),
       set: sandbox.stub(),
       disconnect: sandbox.spy(),
       unpublish: sandbox.spy()
     }, Backbone.Events);
@@ -96,23 +97,24 @@ describe("loop.shared.models", function(
 
           conversation.setupOutgoingCall();
         });
       });
 
       describe("#outgoing", function() {
         beforeEach(function() {
           sandbox.stub(conversation, "endSession");
-          sandbox.stub(conversation, "setSessionData");
+          sandbox.stub(conversation, "setOutgoingSessionData");
+          sandbox.stub(conversation, "setIncomingSessionData");
         });
 
-        it("should save the sessionData", function() {
+        it("should save the outgoing sessionData", function() {
           conversation.outgoing(fakeSessionData);
 
-          sinon.assert.calledOnce(conversation.setSessionData);
+          sinon.assert.calledOnce(conversation.setOutgoingSessionData);
         });
 
         it("should trigger a `call:outgoing` event", function(done) {
           conversation.once("call:outgoing", function() {
             done();
           });
 
           conversation.outgoing();
@@ -134,23 +136,34 @@ describe("loop.shared.models", function(
 
             conversation.outgoing();
 
             sandbox.clock.tick(1001);
           });
       });
 
       describe("#setSessionData", function() {
-        it("should update conversation session information", function() {
-          conversation.setSessionData(fakeSessionData);
+        it("should update outgoing conversation session information",
+           function() {
+             conversation.setOutgoingSessionData(fakeSessionData);
+
+             expect(conversation.get("sessionId")).eql("sessionId");
+             expect(conversation.get("sessionToken")).eql("sessionToken");
+             expect(conversation.get("apiKey")).eql("apiKey");
+           });
 
-          expect(conversation.get("sessionId")).eql("sessionId");
-          expect(conversation.get("sessionToken")).eql("sessionToken");
-          expect(conversation.get("apiKey")).eql("apiKey");
-        });
+        it("should update incoming conversation session information",
+           function() {
+             conversation.setIncomingSessionData(fakeSessionData);
+
+             expect(conversation.get("sessionId")).eql("sessionId");
+             expect(conversation.get("sessionToken")).eql("sessionToken");
+             expect(conversation.get("apiKey")).eql("apiKey");
+             expect(conversation.get("callType")).eql("callType");
+           });
       });
 
       describe("#startSession", function() {
         var model;
 
         beforeEach(function() {
           sandbox.stub(sharedModels.ConversationModel.prototype,
                        "_clearPendingCallTimer");
@@ -354,11 +367,35 @@ describe("loop.shared.models", function(
             sandbox.stub(model, "stopListening");
 
             model.endSession();
             model.trigger("session:ended");
 
             sinon.assert.calledOnce(model.stopListening);
           });
       });
+
+      describe("#hasVideoStream", function() {
+        var model;
+
+        beforeEach(function() {
+          model = new sharedModels.ConversationModel(fakeSessionData, {
+            sdk: fakeSDK,
+            pendingCallTimeout: 1000
+          });
+          model.startSession();
+        });
+
+        it("should return true for incoming callType", function() {
+          model.set("callType", "audio-video");
+
+          expect(model.hasVideoStream("incoming")).to.eql(true);
+        });
+
+        it("should return true for outgoing callType", function() {
+          model.set("selectedCallType", "audio-video");
+
+          expect(model.hasVideoStream("outgoing")).to.eql(true);
+        });
+      });
     });
   });
 });
--- a/browser/components/loop/test/shared/views_test.js
+++ b/browser/components/loop/test/shared/views_test.js
@@ -207,27 +207,47 @@ describe("loop.shared.views", function()
         pendingCallTimeout: 1000
       });
     });
 
     describe("#componentDidMount", function() {
       it("should start a session", function() {
         sandbox.stub(model, "startSession");
 
-        mountTestComponent({sdk: fakeSDK, model: model});
+        mountTestComponent({
+          sdk: fakeSDK,
+          model: model,
+          video: {enabled: true}
+        });
 
         sinon.assert.calledOnce(model.startSession);
       });
+
+      it("should set the correct stream publish options", function() {
+
+        var component = mountTestComponent({
+          sdk: fakeSDK,
+          model: model,
+          video: {enabled: false}
+        });
+
+        expect(component.publisherConfig.publishVideo).to.eql(false);
+
+      });
     });
 
     describe("constructed", function() {
       var comp;
 
       beforeEach(function() {
-        comp = mountTestComponent({sdk: fakeSDK, model: model});
+        comp = mountTestComponent({
+          sdk: fakeSDK,
+          model: model,
+          video: {enabled: false}
+        });
       });
 
       describe("#hangup", function() {
         beforeEach(function() {
           comp.startPublishing();
         });
 
         it("should disconnect the session", function() {
@@ -288,17 +308,21 @@ describe("loop.shared.views", function()
             sinon.assert.calledOnce(fakePublisher.off);
           });
       });
 
       describe("#publishStream", function() {
         var comp;
 
         beforeEach(function() {
-          comp = mountTestComponent({sdk: fakeSDK, model: model});
+          comp = mountTestComponent({
+            sdk: fakeSDK,
+            model: model,
+            video: {enabled: false}
+          });
           comp.startPublishing();
         });
 
         it("should start streaming local audio", function() {
           comp.publishStream("audio", true);
 
           sinon.assert.calledOnce(fakePublisher.publishAudio);
           sinon.assert.calledWithExactly(fakePublisher.publishAudio, true);
--- a/browser/components/loop/test/standalone/webapp_test.js
+++ b/browser/components/loop/test/standalone/webapp_test.js
@@ -297,16 +297,17 @@ describe("loop.webapp", function() {
 
             sinon.assert.calledOnce(notifier.errorL10n);
           });
         });
 
         describe("Has loop token", function() {
           beforeEach(function() {
             conversation.set("loopToken", "fakeToken");
+            conversation.set("selectedCallType", "audio-video");
             sandbox.stub(conversation, "outgoing");
           });
 
           it("should call requestCallInfo on the client",
             function() {
               conversation.setupOutgoingCall();
 
               sinon.assert.calledOnce(client.requestCallInfo);
@@ -395,30 +396,68 @@ describe("loop.webapp", function() {
               model: conversation,
               notifier: notifier,
               client: standaloneClientStub
             })
         );
       });
 
       it("should start the conversation establishment process", function() {
-        var button = view.getDOMNode().querySelector("button");
+        var button = view.getDOMNode().querySelector(".start-audio-video-call");
+        React.addons.TestUtils.Simulate.click(button);
+
+        sinon.assert.calledOnce(setupOutgoingCall);
+        sinon.assert.calledWithExactly(setupOutgoingCall);
+      });
+
+      it("should start the conversation establishment process", function() {
+        var button = view.getDOMNode().querySelector(".start-audio-only-call");
         React.addons.TestUtils.Simulate.click(button);
 
         sinon.assert.calledOnce(setupOutgoingCall);
+        sinon.assert.calledWithExactly(setupOutgoingCall);
       });
 
-      it("should disable current form once session is initiated", function() {
-        conversation.set("loopToken", "fake");
+      it("should disable audio-video button once session is initiated",
+         function() {
+           conversation.set("loopToken", "fake");
+
+           var button = view.getDOMNode().querySelector(".start-audio-video-call");
+           React.addons.TestUtils.Simulate.click(button);
+
+           expect(button.disabled).to.eql(true);
+         });
+
+      it("should disable audio-only button once session is initiated",
+         function() {
+           conversation.set("loopToken", "fake");
+
+           var button = view.getDOMNode().querySelector(".start-audio-only-call");
+           React.addons.TestUtils.Simulate.click(button);
 
-        var button = view.getDOMNode().querySelector("button");
-        React.addons.TestUtils.Simulate.click(button);
+           expect(button.disabled).to.eql(true);
+         });
+
+         it("should set selectedCallType to audio", function() {
+           conversation.set("loopToken", "fake");
+
+           var button = view.getDOMNode().querySelector(".start-audio-only-call");
+           React.addons.TestUtils.Simulate.click(button);
 
-        expect(button.disabled).to.eql(true);
-      });
+           expect(conversation.get("selectedCallType")).to.eql("audio");
+         });
+
+         it("should set selectedCallType to audio-video", function() {
+           conversation.set("loopToken", "fake");
+
+           var button = view.getDOMNode().querySelector(".start-audio-video-call");
+           React.addons.TestUtils.Simulate.click(button);
+
+           expect(conversation.get("selectedCallType")).to.eql("audio-video");
+         });
 
       it("should set state.urlCreationDateString to a locale date string",
          function() {
         // wrap in a jquery object because text is broken up
         // into several span elements
         var date = new Date(0);
         var options = {year: "numeric", month: "long", day: "numeric"};
         var timestamp = date.toLocaleDateString(navigator.language, options);
rename from browser/components/loop/test/xpcshell/test_loopservice_get_loop_char_pref.js
rename to browser/components/loop/test/xpcshell/test_loopservice_loop_prefs.js
--- a/browser/components/loop/test/xpcshell/test_loopservice_get_loop_char_pref.js
+++ b/browser/components/loop/test/xpcshell/test_loopservice_loop_prefs.js
@@ -1,47 +1,106 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 /*global XPCOMUtils, Services, Assert */
 
-var fakePrefName = "color";
+var fakeCharPrefName = "color";
+var fakeBoolPrefName = "boolean";
 var fakePrefValue = "green";
 
 function test_getLoopCharPref()
 {
-  Services.prefs.setCharPref("loop." + fakePrefName, fakePrefValue);
+  Services.prefs.setCharPref("loop." + fakeCharPrefName, fakePrefValue);
 
-  var returnedPref = MozLoopService.getLoopCharPref(fakePrefName);
+  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
 
   Assert.equal(returnedPref, fakePrefValue,
     "Should return a char pref under the loop. branch");
-  Services.prefs.clearUserPref("loop." + fakePrefName);
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
 }
 
 function test_getLoopCharPref_not_found()
 {
-  var returnedPref = MozLoopService.getLoopCharPref(fakePrefName);
+  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
 
   Assert.equal(returnedPref, null,
     "Should return null if a preference is not found");
 }
 
 function test_getLoopCharPref_non_coercible_type()
 {
-  Services.prefs.setBoolPref("loop." + fakePrefName, false );
+  Services.prefs.setBoolPref("loop." + fakeCharPrefName, false);
 
-  var returnedPref = MozLoopService.getLoopCharPref(fakePrefName);
+  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
 
   Assert.equal(returnedPref, null,
     "Should return null if the preference exists & is of a non-coercible type");
 }
 
+function test_setLoopCharPref()
+{
+  Services.prefs.setCharPref("loop." + fakeCharPrefName, "red");
+  MozLoopService.setLoopCharPref(fakeCharPrefName, fakePrefValue);
+
+  var returnedPref = Services.prefs.getCharPref("loop." + fakeCharPrefName);
+
+  Assert.equal(returnedPref, fakePrefValue,
+    "Should set a char pref under the loop. branch");
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+}
+
+function test_setLoopCharPref_new()
+{
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+  MozLoopService.setLoopCharPref(fakeCharPrefName, fakePrefValue);
+
+  var returnedPref = Services.prefs.getCharPref("loop." + fakeCharPrefName);
+
+  Assert.equal(returnedPref, fakePrefValue,
+               "Should set a new char pref under the loop. branch");
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+}
+
+function test_setLoopCharPref_non_coercible_type()
+{
+  MozLoopService.setLoopCharPref(fakeCharPrefName, true);
+
+  ok(true, "Setting non-coercible type should not fail");
+}
+
+
+function test_getLoopBoolPref()
+{
+  Services.prefs.setBoolPref("loop." + fakeBoolPrefName, true);
+
+  var returnedPref = MozLoopService.getLoopBoolPref(fakeBoolPrefName);
+
+  Assert.equal(returnedPref, true,
+    "Should return a bool pref under the loop. branch");
+  Services.prefs.clearUserPref("loop." + fakeBoolPrefName);
+}
+
+function test_getLoopBoolPref_not_found()
+{
+  var returnedPref = MozLoopService.getLoopBoolPref(fakeBoolPrefName);
+
+  Assert.equal(returnedPref, null,
+    "Should return null if a preference is not found");
+}
+
 
 function run_test()
 {
   test_getLoopCharPref();
   test_getLoopCharPref_not_found();
   test_getLoopCharPref_non_coercible_type();
+  test_setLoopCharPref();
+  test_setLoopCharPref_new();
+  test_setLoopCharPref_non_coercible_type();
+
+  test_getLoopBoolPref();
+  test_getLoopBoolPref_not_found();
 
   do_register_cleanup(function() {
-    Services.prefs.clearUserPref("loop." + fakePrefName);
+    Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+    Services.prefs.clearUserPref("loop." + fakeBoolPrefName);
   });
 }
deleted file mode 100644
--- a/browser/components/loop/test/xpcshell/test_loopservice_set_loop_char_pref.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-/*global XPCOMUtils, Services, Assert */
-
-var fakePrefName = "color";
-var fakePrefValue = "green";
-
-function test_setLoopCharPref()
-{
-  Services.prefs.setCharPref("loop." + fakePrefName, "red");
-  MozLoopService.setLoopCharPref(fakePrefName, fakePrefValue);
-
-  var returnedPref = Services.prefs.getCharPref("loop." + fakePrefName);
-
-  Assert.equal(returnedPref, fakePrefValue,
-    "Should set a char pref under the loop. branch");
-  Services.prefs.clearUserPref("loop." + fakePrefName);
-}
-
-function test_setLoopCharPref_new()
-{
-  Services.prefs.clearUserPref("loop." + fakePrefName);
-  MozLoopService.setLoopCharPref(fakePrefName, fakePrefValue);
-
-  var returnedPref = Services.prefs.getCharPref("loop." + fakePrefName);
-
-  Assert.equal(returnedPref, fakePrefValue,
-               "Should set a new char pref under the loop. branch");
-  Services.prefs.clearUserPref("loop." + fakePrefName);
-}
-
-function test_setLoopCharPref_non_coercible_type()
-{
-  MozLoopService.setLoopCharPref(fakePrefName, true);
-
-  ok(true, "Setting non-coercible type should not fail");
-}
-
-
-function run_test()
-{
-  test_setLoopCharPref();
-  test_setLoopCharPref_new();
-  test_setLoopCharPref_non_coercible_type();
-
-  do_register_cleanup(function() {
-    Services.prefs.clearUserPref("loop." + fakePrefName);
-  });
-}
--- a/browser/components/loop/test/xpcshell/xpcshell.ini
+++ b/browser/components/loop/test/xpcshell/xpcshell.ini
@@ -1,17 +1,16 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
 
 [test_looppush_initialize.js]
 [test_loopservice_dnd.js]
 [test_loopservice_expiry.js]
-[test_loopservice_get_loop_char_pref.js]
-[test_loopservice_set_loop_char_pref.js]
+[test_loopservice_loop_prefs.js]
 [test_loopservice_initialize.js]
 [test_loopservice_locales.js]
 [test_loopservice_registration.js]
 [test_loopservice_token_invalid.js]
 [test_loopservice_token_save.js]
 [test_loopservice_token_send.js]
 [test_loopservice_token_validation.js]
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -3,17 +3,17 @@
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <?xml-stylesheet href="chrome://global/skin/global.css"?>
 
 <?xml-stylesheet href="chrome://mozapps/content/preferences/preferences.css"?>
 
 <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
-<?xml-stylesheet href="chrome://browser/skin/in-content/common.css"?>
+<?xml-stylesheet href="chrome://global/skin/in-content/common.css"?>
 <?xml-stylesheet
   href="chrome://browser/skin/preferences/in-content/preferences.css"?>
 <?xml-stylesheet
   href="chrome://browser/content/preferences/handlers.css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/applications.css"?>
 
 <!DOCTYPE page [
 <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
--- a/browser/components/preferences/in-content/subdialogs.js
+++ b/browser/components/preferences/in-content/subdialogs.js
@@ -6,17 +6,17 @@
 
 let gSubDialog = {
   _closingCallback: null,
   _frame: null,
   _overlay: null,
   _box: null,
   _injectedStyleSheets: ["chrome://mozapps/content/preferences/preferences.css",
                          "chrome://browser/skin/preferences/preferences.css",
-                         "chrome://browser/skin/in-content/common.css",
+                         "chrome://global/skin/in-content/common.css",
                          "chrome://browser/skin/preferences/in-content/preferences.css"],
 
   init: function() {
     this._frame = document.getElementById("dialogFrame");
     this._overlay = document.getElementById("dialogOverlay");
     this._box = document.getElementById("dialogBox");
 
     // Make the close button work.
--- a/browser/devtools/framework/test/browser_dynamic_tool_enabling.js
+++ b/browser/devtools/framework/test/browser_dynamic_tool_enabling.js
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that toggling prefs immediately (de)activates the relevant menuitem
 
 let gItemsToTest = {
   "menu_devToolbar": "devtools.toolbar.enabled",
-  "menu_devAppMgr": "devtools.appmanager.enabled",
   "menu_browserToolbox": ["devtools.chrome.enabled", "devtools.debugger.remote-enabled", "devtools.debugger.chrome-enabled"],
   "javascriptConsole": "devtools.errorconsole.enabled",
   "menu_devtools_connect": "devtools.debugger.remote-enabled",
 };
 
 function expectedAttributeValueFromPrefs(prefs) {
   return prefs.every((pref) => Services.prefs.getBoolPref(pref)) ?
          "" : "true";
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -71,16 +71,17 @@ function Toolbox(target, selectedTool, h
   this._refreshHostTitle = this._refreshHostTitle.bind(this);
   this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this);
   this.destroy = this.destroy.bind(this);
   this.highlighterUtils = getHighlighterUtils(this);
   this._highlighterReady = this._highlighterReady.bind(this);
   this._highlighterHidden = this._highlighterHidden.bind(this);
   this._prefChanged = this._prefChanged.bind(this);
   this._saveSplitConsoleHeight = this._saveSplitConsoleHeight.bind(this);
+  this._onFocus = this._onFocus.bind(this);
 
   this._target.on("close", this.destroy);
 
   if (!hostType) {
     hostType = Services.prefs.getCharPref(this._prefs.LAST_HOST);
   }
   if (!selectedTool) {
     selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
@@ -248,36 +249,39 @@ Toolbox.prototype = {
         gDevTools.on("pref-changed", this._prefChanged);
 
         this._buildDockButtons();
         this._buildOptions();
         this._buildTabs();
         this._applyCacheSettings();
         this._addKeysToWindow();
         this._addReloadKeys();
-        this._addToolSwitchingKeys();
+        this._addHostListeners();
         this._addZoomKeys();
         this._loadInitialZoom();
 
         this.webconsolePanel = this.doc.querySelector("#toolbox-panel-webconsole");
         this.webconsolePanel.height =
           Services.prefs.getIntPref(SPLITCONSOLE_HEIGHT_PREF);
         this.webconsolePanel.addEventListener("resize",
           this._saveSplitConsoleHeight);
 
-        let splitConsolePromise = promise.resolve();
-        if (Services.prefs.getBoolPref(SPLITCONSOLE_ENABLED_PREF)) {
-          splitConsolePromise = this.openSplitConsole();
-        }
-
         let buttonsPromise = this._buildButtons();
 
         this._telemetry.toolOpened("toolbox");
 
         this.selectTool(this._defaultToolId).then(panel => {
+
+          // Wait until the original tool is selected so that the split
+          // console input will receive focus.
+          let splitConsolePromise = promise.resolve();
+          if (Services.prefs.getBoolPref(SPLITCONSOLE_ENABLED_PREF)) {
+            splitConsolePromise = this.openSplitConsole();
+          }
+
           promise.all([
             splitConsolePromise,
             buttonsPromise
           ]).then(() => {
             this.emit("ready");
             deferred.resolve();
           }, deferred.reject);
         });
@@ -340,25 +344,27 @@ Toolbox.prototype = {
       ["toolbox-force-reload-key2", true]
     ].forEach(([id, force]) => {
       this.doc.getElementById(id).addEventListener("command", (event) => {
         this.reloadTarget(force);
       }, true);
     });
   },
 
-  _addToolSwitchingKeys: function() {
+  _addHostListeners: function() {
     let nextKey = this.doc.getElementById("toolbox-next-tool-key");
     nextKey.addEventListener("command", this.selectNextTool.bind(this), true);
     let prevKey = this.doc.getElementById("toolbox-previous-tool-key");
     prevKey.addEventListener("command", this.selectPreviousTool.bind(this), true);
 
     // Split console uses keypress instead of command so the event can be
     // cancelled with stopPropagation on the keypress, and not preventDefault.
     this.doc.addEventListener("keypress", this._splitConsoleOnKeypress, false);
+
+    this.doc.addEventListener("focus", this._onFocus, true);
   },
 
   _saveSplitConsoleHeight: function() {
     Services.prefs.setIntPref(SPLITCONSOLE_HEIGHT_PREF,
       this.webconsolePanel.height);
   },
 
   /**
@@ -971,49 +977,71 @@ Toolbox.prototype = {
     let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id);
     iframe.focus();
   },
 
   /**
    * Focus split console's input line
    */
   focusConsoleInput: function() {
-    let hud = this.getPanel("webconsole").hud;
-    if (hud && hud.jsterm) {
-      hud.jsterm.inputNode.focus();
+    let consolePanel = this.getPanel("webconsole");
+    if (consolePanel) {
+      consolePanel.focusInput();
     }
   },
 
   /**
+   * If the console is split and we are focusing an element outside
+   * of the console, then store the newly focused element, so that
+   * it can be restored once the split console closes.
+   */
+  _onFocus: function({originalTarget}) {
+    // Ignore any non element nodes, or any elements contained
+    // within the webconsole frame.
+    let webconsoleURL = gDevTools.getToolDefinition("webconsole").url;
+    if (originalTarget.nodeType !== 1 ||
+        originalTarget.baseURI === webconsoleURL) {
+      return;
+    }
+
+    this._lastFocusedElement = originalTarget;
+  },
+
+  /**
    * Opens the split console.
    *
    * @returns {Promise} a promise that resolves once the tool has been
    *          loaded and focused.
    */
   openSplitConsole: function() {
     this._splitConsole = true;
     Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, true);
     this._refreshConsoleDisplay();
     this.emit("split-console");
+
     return this.loadTool("webconsole").then(() => {
       this.focusConsoleInput();
     });
   },
 
   /**
    * Closes the split console.
    *
    * @returns {Promise} a promise that resolves once the tool has been
    *          closed.
    */
   closeSplitConsole: function() {
     this._splitConsole = false;
     Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, false);
     this._refreshConsoleDisplay();
     this.emit("split-console");
+
+    if (this._lastFocusedElement) {
+      this._lastFocusedElement.focus();
+    }
     return promise.resolve();
   },
 
   /**
    * Toggles the split state of the webconsole.  If the webconsole panel
    * is already selected then this command is ignored.
    *
    * @returns {Promise} a promise that resolves once the tool has been
@@ -1307,16 +1335,17 @@ Toolbox.prototype = {
   /**
    * Destroy the current host, and remove event listeners from its frame.
    *
    * @return {promise} to be resolved when the host is destroyed.
    */
   destroyHost: function() {
     this.doc.removeEventListener("keypress",
       this._splitConsoleOnKeypress, false);
+    this.doc.removeEventListener("focus", this._onFocus, true);
     return this._host.destroy();
   },
 
   /**
    * Remove all UI elements, detach from target and clear up
    */
   destroy: function() {
     // If several things call destroy then we give them all the same
@@ -1329,16 +1358,17 @@ Toolbox.prototype = {
     this.off("select", this._refreshHostTitle);
     this.off("host-changed", this._refreshHostTitle);
 
     gDevTools.off("tool-registered", this._toolRegistered);
     gDevTools.off("tool-unregistered", this._toolUnregistered);
 
     gDevTools.off("pref-changed", this._prefChanged);
 
+    this._lastFocusedElement = null;
     this._saveSplitConsoleHeight();
     this.webconsolePanel.removeEventListener("resize",
       this._saveSplitConsoleHeight);
     this.closeButton.removeEventListener("command", this.destroy, true);
 
     let outstanding = [];
     for (let [id, panel] of this._toolPanels) {
       try {
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -1609,18 +1609,21 @@ var Scratchpad = {
     };
 
     this.editor = new Editor(config);
     let editorElement = document.querySelector("#scratchpad-editor");
     this.editor.appendTo(editorElement).then(() => {
       var lines = initialText.split("\n");
 
       this.editor.on("change", this._onChanged);
+      let okstring = this.strings.GetStringFromName("selfxss.okstring");
+      let msg = this.strings.formatStringFromName("selfxss.msg", [okstring], 1);
       this._onPaste = WebConsoleUtils.pasteHandlerGen(this.editor.container.contentDocument.body,
-                                                      document.querySelector('#scratchpad-notificationbox'));
+                                                      document.querySelector('#scratchpad-notificationbox'),
+                                                      msg, okstring);
       editorElement.addEventListener("paste", this._onPaste);
       editorElement.addEventListener("drop", this._onPaste);
       this.editor.on("save", () => this.saveFile());
       this.editor.focus();
       this.editor.setCursor({ line: lines.length, ch: lines.pop().length });
 
       if (state)
         this.dirty = !state.saved;
--- a/browser/devtools/webaudioeditor/test/browser_wa_inspector-toggle.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_inspector-toggle.js
@@ -53,14 +53,14 @@ function spawnTest() {
 
   click(panelWin, findGraphNode(panelWin, nodeIds[1]));
   yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
 
   ok(!isVisible($("#web-audio-editor-details-pane-empty")),
     "Empty message hides even when loading node while open.");
   ok(isVisible($("#web-audio-editor-tabs")),
     "Switches to tab view when loading node while open.");
-  is($("#web-audio-inspector-title").value, "OscillatorNode (" + nodeIds[1] + ")",
+  is($("#web-audio-inspector-title").value, "Oscillator",
     "Inspector title updates when loading node while open.");
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/webaudioeditor/test/browser_wa_inspector.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_inspector.js
@@ -38,23 +38,23 @@ function spawnTest() {
   ]);
 
   ok(WebAudioInspectorView.isVisible(), "InspectorView shown once node selected.");
   ok(!isVisible($("#web-audio-editor-details-pane-empty")),
     "InspectorView empty message hidden when node selected.");
   ok(isVisible($("#web-audio-editor-tabs")),
     "InspectorView tabs view visible when node selected.");
 
-  is($("#web-audio-inspector-title").value, "OscillatorNode (" + nodeIds[1] + ")",
+  is($("#web-audio-inspector-title").value, "Oscillator",
     "Inspector should have the node title when a node is selected.");
 
   is($("#web-audio-editor-tabs").selectedIndex, 0,
     "default tab selected should be the parameters tab.");
 
   click(panelWin, findGraphNode(panelWin, nodeIds[2]));
   yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
 
-  is($("#web-audio-inspector-title").value, "GainNode (" + nodeIds[2] + ")",
+  is($("#web-audio-inspector-title").value, "Gain",
     "Inspector title updates when a new node is selected.");
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/webaudioeditor/webaudioeditor-view.js
+++ b/browser/devtools/webaudioeditor/webaudioeditor-view.js
@@ -151,17 +151,21 @@ let WebAudioGraphView = {
     // Clear out previous SVG information
     this.clearGraph();
 
     let graph = new dagreD3.Digraph();
     let edges = [];
 
     AudioNodes.forEach(node => {
       // Add node to graph
-      graph.addNode(node.id, { label: node.type, id: node.id });
+      graph.addNode(node.id, {
+        type: node.type,                        // Just for storing type data
+        label: node.type.replace(/Node$/, ""),  // Displayed in SVG node
+        id: node.id                             // Identification
+      });
 
       // Add all of the connections from this node to the edge array to be added
       // after all the nodes are added, otherwise edges will attempted to be created
       // for nodes that have not yet been added
       AudioNodeConnections.get(node, new Set()).forEach(dest => edges.push([node, dest]));
     });
 
     edges.forEach(([node, dest]) => graph.addEdge(null, node.id, dest.id, {
@@ -172,17 +176,17 @@ let WebAudioGraphView = {
     let renderer = new dagreD3.Renderer();
 
     // Post-render manipulation of the nodes
     let oldDrawNodes = renderer.drawNodes();
     renderer.drawNodes(function(graph, root) {
       let svgNodes = oldDrawNodes(graph, root);
       svgNodes.attr("class", (n) => {
         let node = graph.node(n);
-        return "audionode type-" + node.label;
+        return "audionode type-" + node.type;
       });
       svgNodes.attr("data-id", (n) => {
         let node = graph.node(n);
         return node.id;
       });
       return svgNodes;
     });
 
@@ -447,17 +451,17 @@ let WebAudioInspectorView = {
     this.toggleInspector({ visible: false, animated: false, delayed: false });
   },
 
   /**
    * Sets the title of the Inspector view
    */
   _setTitle: function () {
     let node = this._currentNode;
-    let title = node.type + " (" + node.id + ")";
+    let title = node.type.replace(/Node$/, "");
     $("#web-audio-inspector-title").setAttribute("value", title);
   },
 
   /**
    * Reconstructs the `Properties` tab in the inspector
    * with the `this._currentNode` as it's source.
    */
   _buildPropertiesView: Task.async(function* () {
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -276,16 +276,17 @@ skip-if = buildapp == 'mulet'
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_output_copy_newlines.js]
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 [browser_webconsole_scratchpad_panel_link.js]
 [browser_webconsole_split.js]
 [browser_webconsole_split_escape_key.js]
+[browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
 [browser_webconsole_view_source.js]
 [browser_webconsole_reflow.js]
 [browser_webconsole_log_file_filter.js]
 [browser_webconsole_expandable_timestamps.js]
 [browser_webconsole_autocomplete_in_debugger_stackframe.js]
 [browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
 [browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_focus.js
@@ -0,0 +1,74 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+  info("Test that the split console state is persisted");
+
+  let toolbox;
+  let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
+
+  Task.spawn(runner).then(finish);
+
+  function* runner() {
+    info("Opening a tab while there is no user setting on split console pref");
+    let {tab} = yield loadTab(TEST_URI);
+    let target = TargetFactory.forTab(tab);
+    toolbox = yield gDevTools.showToolbox(target, "inspector");
+
+    ok(!toolbox.splitConsole, "Split console is hidden by default");
+
+    info ("Focusing the search box before opening the split console");
+    let inspector = toolbox.getPanel("inspector");
+    inspector.searchBox.focus();
+
+    // Use the binding element since inspector.searchBox is a XUL element.
+    let activeElement = getActiveElement(inspector.panelDoc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    is (activeElement, inspector.searchBox, "Search box is focused");
+
+    yield toolbox.openSplitConsole();
+
+    ok(toolbox.splitConsole, "Split console is now visible");
+
+    // Use the binding element since jsterm.inputNode is a XUL textarea element.
+    let activeElement = getActiveElement(toolbox.doc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+    is(activeElement, inputNode, "Split console input is focused by default");
+
+    yield toolbox.closeSplitConsole();
+
+    info ("Making sure that the search box is refocused after closing the split console");
+    // Use the binding element since inspector.searchBox is a XUL element.
+    let activeElement = getActiveElement(inspector.panelDoc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    is (activeElement, inspector.searchBox, "Search box is focused");
+
+    yield toolbox.destroy();
+  }
+
+  function getActiveElement(doc) {
+    let activeElement = doc.activeElement;
+    while (activeElement && activeElement.contentDocument) {
+      activeElement = activeElement.contentDocument.activeElement;
+    }
+    return activeElement;
+  }
+
+  function toggleSplitConsoleWithEscape() {
+    let onceSplitConsole = toolbox.once("split-console");
+    let contentWindow = toolbox.frame.contentWindow;
+    contentWindow.focus();
+    EventUtils.sendKey("ESCAPE", contentWindow);
+    return onceSplitConsole;
+  }
+
+  function finish() {
+    toolbox = TEST_URI = null;
+    Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
+    Services.prefs.clearUserPref("devtools.toolbox.splitconsoleHeight");
+    finishTest();
+  }
+}
--- a/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
@@ -30,16 +30,22 @@ function test() {
     info("Opening a tab while there is a true user setting on split console pref");
     let {tab} = yield loadTab(TEST_URI);
     let target = TargetFactory.forTab(tab);
     toolbox = yield gDevTools.showToolbox(target, "inspector");
 
     ok(toolbox.splitConsole, "Split console is visible by default.");
     is(getHeightPrefValue(), 200, "Height is set based on panel height after closing");
 
+    // Use the binding element since jsterm.inputNode is a XUL textarea element.
+    let activeElement = getActiveElement(toolbox.doc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+    is(activeElement, inputNode, "Split console input is focused by default");
+
     toolbox.webconsolePanel.height = 1;
     ok (toolbox.webconsolePanel.clientHeight > 1,
         "The actual height of the console is bound with a min height");
 
     toolbox.webconsolePanel.height = 10000;
     ok (toolbox.webconsolePanel.clientHeight < 10000,
         "The actual height of the console is bound with a max height");
 
@@ -58,16 +64,24 @@ function test() {
     toolbox = yield gDevTools.showToolbox(target, "inspector");
 
     ok(!toolbox.splitConsole, "Split console is hidden by default.");
     ok(!getVisiblePrefValue(), "Visibility pref is false");
 
     yield toolbox.destroy();
   }
 
+  function getActiveElement(doc) {
+    let activeElement = doc.activeElement;
+    while (activeElement && activeElement.contentDocument) {
+      activeElement = activeElement.contentDocument.activeElement;
+    }
+    return activeElement;
+  }
+
   function getVisiblePrefValue() {
     return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled");
   }
 
   function getHeightPrefValue() {
     return Services.prefs.getIntPref("devtools.toolbox.splitconsoleHeight");
   }
 
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -3132,17 +3132,21 @@ JSTerm.prototype = {
     this.completeNode = doc.querySelector(".jsterm-complete-node");
     this.inputNode = doc.querySelector(".jsterm-input-node");
 
     if (this.hud.owner._browserConsole &&
         !Services.prefs.getBoolPref("devtools.chrome.enabled")) {
       inputContainer.style.display = "none";
     }
     else {
-      this._onPaste = WebConsoleUtils.pasteHandlerGen(this.inputNode, doc.getElementById("webconsole-notificationbox"));
+      let okstring = l10n.getStr("selfxss.okstring");
+      let msg = l10n.getFormatStr("selfxss.msg", [okstring]);
+      this._onPaste = WebConsoleUtils.pasteHandlerGen(this.inputNode,
+                                                      doc.getElementById("webconsole-notificationbox"),
+                                                      msg, okstring);
       this.inputNode.addEventListener("keypress", this._keyPress, false);
       this.inputNode.addEventListener("paste", this._onPaste);
       this.inputNode.addEventListener("drop", this._onPaste);
       this.inputNode.addEventListener("input", this._inputEventHandler, false);
       this.inputNode.addEventListener("keyup", this._inputEventHandler, false);
       this.inputNode.addEventListener("focus", this._focusEventHandler, false);
     }
 
--- a/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties
@@ -98,8 +98,18 @@ scratchpad.label=Scratchpad
 # LOCALIZATION NOTE (scratchpad.panelLabel): this is used as the
 # label for the toolbox panel.
 scratchpad.panelLabel=Scratchpad Panel
 
 # LOCALIZATION NOTE (scratchpad.tooltip):  This string is displayed in the
 # tooltip of the tab when the Scratchpad is displayed inside the developer tools
 # window.
 scratchpad.tooltip=Scratchpad
+
+# LOCALIZATION NOTE (selfxss.msg): the text that is displayed when
+# a new user of the developer tools pastes code into the console
+# %1 is the text of selfxss.okstring
+selfxss.msg=Scam Warning: Take care when pasting things you don't understand. This could allow attackers to steal your identity or take control of your computer. Please type '%S' in the scratchpad below to allow pasting.
+
+# LOCALIZATION NOTE (selfxss.msg): the string to be typed
+# in by a new user of the developer tools when they receive the sefxss.msg prompt.
+# Please avoid using non-keyboard characters here
+selfxss.okstring=allow pasting
--- a/browser/locales/en-US/chrome/browser/loop/loop.properties
+++ b/browser/locales/en-US/chrome/browser/loop/loop.properties
@@ -12,16 +12,17 @@ display_name_available_status=Available
 
 unable_retrieve_url=Sorry, we were unable to retrieve a call url.
 
 # Conversation Window Strings
 
 incoming_call_title=Incoming Call…
 incoming_call=Incoming call
 incoming_call_answer_button=Answer
+incoming_call_answer_audio_only_tooltip=Answer with voice
 incoming_call_decline_button=Decline
 incoming_call_decline_and_block_button=Decline and Block
 incoming_call_block_button=Block
 hangup_button_title=Hangup
 mute_local_audio_button_title=Mute your audio
 unmute_local_audio_button_title=Unmute your audio
 mute_local_video_button_title=Mute your video
 unmute_local_video_button_title=Unmute your video
--- a/browser/modules/AboutHome.jsm
+++ b/browser/modules/AboutHome.jsm
@@ -246,9 +246,18 @@ let AboutHome = {
       } else {
         let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
         mm.broadcastAsyncMessage("AboutHome:Update", data);
       }
     }).then(null, function onError(x) {
       Cu.reportError("Error in AboutHome.sendAboutHomeData: " + x);
     });
   },
+
+  /**
+   * Focuses the search input in the page with the given message manager.
+   * @param  messageManager
+   *         The MessageManager object of the selected browser.
+   */
+  focusInput: function (messageManager) {
+    messageManager.sendAsyncMessage("AboutHome:FocusInput");
+  }
 };
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -89,16 +89,27 @@ this.ContentSearch = {
 
   init: function () {
     Cc["@mozilla.org/globalmessagemanager;1"].
       getService(Ci.nsIMessageListenerManager).
       addMessageListener(INBOUND_MESSAGE, this);
     Services.obs.addObserver(this, "browser-search-engine-modified", false);
   },
 
+  /**
+   * Focuses the search input in the page with the given message manager.
+   * @param  messageManager
+   *         The MessageManager object of the selected browser.
+   */
+  focusInput: function (messageManager) {
+    messageManager.sendAsyncMessage(OUTBOUND_MESSAGE, {
+      type: "FocusInput"
+    });
+  },
+
   receiveMessage: function (msg) {
     // Add a temporary event handler that exists only while the message is in
     // the event queue.  If the message's source docshell changes browsers in
     // the meantime, then we need to update msg.target.  event.detail will be
     // the docshell's new parent <xul:browser> element.
     msg.handleEvent = event => {
       let browserData = this._suggestionMap.get(msg.target);
       if (browserData) {
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -876,17 +876,16 @@ toolbarbutton[sdk-button="true"][cui-are
   -moz-box-direction: reverse;
 }
 
 #urlbar-icons {
   -moz-box-align: center;
 }
 
 .urlbar-icon {
-  cursor: pointer;
   padding: 0 3px;
 }
 
 #urlbar-search-splitter {
   -moz-appearance: none;
   width: 8px;
   -moz-margin-start: -4px;
 }
@@ -1519,17 +1518,16 @@ richlistitem[type~="action"][actiontype=
   border-top: 1px solid GrayText;
 }
 
 /* Combined go/reload/stop button in location bar */
 
 #urlbar > toolbarbutton {
   -moz-appearance: none;
   padding: 0 2px;
-  cursor: pointer;
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
 }
 
 #urlbar-reload-button {
   -moz-image-region: rect(0, 14px, 14px, 0);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -30,27 +30,16 @@ browser.jar:
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
   skin/classic/browser/identity-icons-https-mixed-active.png
   skin/classic/browser/identity-icons-https-mixed-display.png
   skin/classic/browser/Info.png
-* skin/classic/browser/in-content/common.css                    (in-content/common.css)
-  skin/classic/browser/in-content/check.png                 (../shared/in-content/check.png)
-  skin/classic/browser/in-content/check@2x.png              (../shared/in-content/check@2x.png)
-  skin/classic/browser/in-content/dropdown.png              (../shared/in-content/dropdown.png)
-  skin/classic/browser/in-content/dropdown@2x.png           (../shared/in-content/dropdown@2x.png)
-  skin/classic/browser/in-content/dropdown-disabled.png     (../shared/in-content/dropdown-disabled.png)
-  skin/classic/browser/in-content/dropdown-disabled@2x.png  (../shared/in-content/dropdown-disabled@2x.png)
-  skin/classic/browser/in-content/help-glyph.png            (../shared/in-content/help-glyph.png)
-  skin/classic/browser/in-content/help-glyph@2x.png         (../shared/in-content/help-glyph@2x.png)
-  skin/classic/browser/in-content/sorter.png                (../shared/in-content/sorter.png)
-  skin/classic/browser/in-content/sorter@2x.png             (../shared/in-content/sorter@2x.png)
   skin/classic/browser/menuPanel.png
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-small.png
   skin/classic/browser/mixed-content-blocked-16.png
   skin/classic/browser/mixed-content-blocked-64.png
   skin/classic/browser/monitor.png
--- a/browser/themes/linux/searchbar.css
+++ b/browser/themes/linux/searchbar.css
@@ -52,17 +52,16 @@
 /* Search go button */
 .search-go-container {
   -moz-box-align: center;
 }
 
 .search-go-button {
   padding: 1px;
   list-style-image: url(moz-icon://stock/gtk-find?size=menu);
-  cursor: pointer;
 }
 
 menuitem[cmd="cmd_clearhistory"] {
   list-style-image: url("moz-icon://stock/gtk-clear?size=menu");
 }
 
 menuitem[cmd="cmd_clearhistory"][disabled] {
   list-style-image: url("moz-icon://stock/gtk-clear?size=menu&state=disabled");
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -38,27 +38,16 @@ browser.jar:
   skin/classic/browser/identity-icons-https@2x.png
   skin/classic/browser/identity-icons-https-ev.png
   skin/classic/browser/identity-icons-https-ev@2x.png
   skin/classic/browser/identity-icons-https-mixed-active.png
   skin/classic/browser/identity-icons-https-mixed-active@2x.png
   skin/classic/browser/identity-icons-https-mixed-display.png
   skin/classic/browser/identity-icons-https-mixed-display@2x.png
   skin/classic/browser/Info.png
-* skin/classic/browser/in-content/common.css                (in-content/common.css)
-  skin/classic/browser/in-content/check.png                 (../shared/in-content/check.png)
-  skin/classic/browser/in-content/check@2x.png              (../shared/in-content/check@2x.png)
-  skin/classic/browser/in-content/dropdown.png              (../shared/in-content/dropdown.png)
-  skin/classic/browser/in-content/dropdown@2x.png           (../shared/in-content/dropdown@2x.png)
-  skin/classic/browser/in-content/dropdown-disabled.png     (../shared/in-content/dropdown-disabled.png)
-  skin/classic/browser/in-content/dropdown-disabled@2x.png  (../shared/in-content/dropdown-disabled@2x.png)
-  skin/classic/browser/in-content/help-glyph.png            (../shared/in-content/help-glyph.png)
-  skin/classic/browser/in-content/help-glyph@2x.png         (../shared/in-content/help-glyph@2x.png)
-  skin/classic/browser/in-content/sorter.png                (../shared/in-content/sorter.png)
-  skin/classic/browser/in-content/sorter@2x.png             (../shared/in-content/sorter@2x.png)
   skin/classic/browser/keyhole-circle.png
   skin/classic/browser/keyhole-circle@2x.png
   skin/classic/browser/KUI-background.png
   skin/classic/browser/subtle-pattern.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
   skin/classic/browser/notification-16.png
   skin/classic/browser/notification-16@2x.png
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -892,24 +892,24 @@ toolbarbutton[panel-multiview-anchor="tr
   background-repeat: no-repeat;
   background-color: Highlight;
   background-position: left 10px center, 0; /* this doesn't need to be changed for RTL */
 }
 
 toolbarbutton[panel-multiview-anchor="true"] {
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted.png),
                     linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
-  background-position: right 5px center;
+  background-position: right calc(@menuPanelButtonWidth@ / 2 - @exitSubviewGutterWidth@ + 2px) center;
   background-repeat: no-repeat, repeat;
 }
 
 toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl.png),
                     linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
-  background-position: left 5px center;
+  background-position: left calc(@menuPanelButtonWidth@ / 2 - @exitSubviewGutterWidth@ + 2px) center;
 }
 
 toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
 #bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-dropmarker {
   display: none;
 }
 
 #search-container[cui-areatype="menu-panel"],
--- a/browser/themes/shared/devtools/webaudioeditor.inc.css
+++ b/browser/themes/shared/devtools/webaudioeditor.inc.css
@@ -94,16 +94,20 @@ text {
 .theme-light g.selected text {
   fill: #f0f1f2; /* Toolbars */
 }
 
 /**
  * Inspector Styles
  */
 
+#web-audio-inspector-title {
+  margin: 6px;
+}
+
 .web-audio-inspector .error {
   background-image: url(alerticon-warning.png);
   background-size: 13px 12px;
   -moz-appearance: none;
   opacity: 0;
   transition: opacity .5s ease-out 0s;
 }
 
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -162,32 +162,32 @@ prefpane {
   padding: 0 10px;
 }
 
 #typeColumn > .treecol-sortdirection[sortDirection=ascending],
 #actionColumn > .treecol-sortdirection[sortDirection=ascending],
 #typeColumn > .treecol-sortdirection[sortDirection=descending],
 #actionColumn > .treecol-sortdirection[sortDirection=descending] {
   -moz-appearance: none;
-  list-style-image: url("chrome://browser/skin/in-content/sorter.png");
+  list-style-image: url("chrome://global/skin/in-content/sorter.png");
 }
 
 #typeColumn > .treecol-sortdirection[sortDirection=descending],
 #actionColumn > .treecol-sortdirection[sortDirection=descending] {
   transform: scaleY(-1);
 }
 
 @media (min-resolution: 2dppx) {
   #typeColumn > .treecol-sortdirection[sortDirection=ascending],
   #actionColumn > .treecol-sortdirection[sortDirection=ascending],
   #typeColumn > .treecol-sortdirection[sortDirection=descending],
   #actionColumn > .treecol-sortdirection[sortDirection=descending] {
     width: 12px;
     height: 8px;
-    list-style-image: url("chrome://browser/skin/in-content/sorter@2x.png");
+    list-style-image: url("chrome://global/skin/in-content/sorter@2x.png");
   }
 }
 
 #handlersView > richlistitem {
   min-height: 40px !important;
 }
 
 .typeIcon {
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -32,27 +32,16 @@ browser.jar:
         skin/classic/browser/Geolocation-64.png
         skin/classic/browser/Info.png
         skin/classic/browser/identity.png
         skin/classic/browser/identity-icons-generic.png
         skin/classic/browser/identity-icons-https.png
         skin/classic/browser/identity-icons-https-ev.png
         skin/classic/browser/identity-icons-https-mixed-active.png
         skin/classic/browser/identity-icons-https-mixed-display.png
-*       skin/classic/browser/in-content/common.css                  (in-content/common.css)
-        skin/classic/browser/in-content/check.png                   (../shared/in-content/check.png)
-        skin/classic/browser/in-content/check@2x.png                (../shared/in-content/check@2x.png)
-        skin/classic/browser/in-content/dropdown.png                (../shared/in-content/dropdown.png)
-        skin/classic/browser/in-content/dropdown@2x.png             (../shared/in-content/dropdown@2x.png)
-        skin/classic/browser/in-content/dropdown-disabled.png       (../shared/in-content/dropdown-disabled.png)
-        skin/classic/browser/in-content/dropdown-disabled@2x.png    (../shared/in-content/dropdown-disabled@2x.png)
-        skin/classic/browser/in-content/help-glyph.png              (../shared/in-content/help-glyph.png)
-        skin/classic/browser/in-content/help-glyph@2x.png           (../shared/in-content/help-glyph@2x.png)
-        skin/classic/browser/in-content/sorter.png                  (../shared/in-content/sorter.png)
-        skin/classic/browser/in-content/sorter@2x.png               (../shared/in-content/sorter@2x.png)
         skin/classic/browser/keyhole-forward-mask.svg
         skin/classic/browser/KUI-background.png
         skin/classic/browser/livemark-folder.png
         skin/classic/browser/menu-back.png
         skin/classic/browser/menu-forward.png
         skin/classic/browser/menuPanel.png
         skin/classic/browser/menuPanel-customize.png
         skin/classic/browser/menuPanel-exit.png
@@ -452,27 +441,16 @@ browser.jar:
         skin/classic/aero/browser/Geolocation-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/identity-icons-generic.png
         skin/classic/aero/browser/identity-icons-https.png
         skin/classic/aero/browser/identity-icons-https-ev.png
         skin/classic/aero/browser/identity-icons-https-mixed-active.png
         skin/classic/aero/browser/identity-icons-https-mixed-display.png
-*       skin/classic/aero/browser/in-content/common.css               (in-content/common.css)
-        skin/classic/aero/browser/in-content/check.png                (../shared/in-content/check.png)
-        skin/classic/aero/browser/in-content/check@2x.png             (../shared/in-content/check@2x.png)
-        skin/classic/aero/browser/in-content/dropdown.png             (../shared/in-content/dropdown.png)
-        skin/classic/aero/browser/in-content/dropdown@2x.png          (../shared/in-content/dropdown@2x.png)
-        skin/classic/aero/browser/in-content/dropdown-disabled.png    (../shared/in-content/dropdown-disabled.png)
-        skin/classic/aero/browser/in-content/dropdown-disabled@2x.png (../shared/in-content/dropdown-disabled@2x.png)
-        skin/classic/aero/browser/in-content/help-glyph.png           (../shared/in-content/help-glyph.png)
-        skin/classic/aero/browser/in-content/help-glyph@2x.png        (../shared/in-content/help-glyph@2x.png)
-        skin/classic/aero/browser/in-content/sorter.png               (../shared/in-content/sorter.png)
-        skin/classic/aero/browser/in-content/sorter@2x.png            (../shared/in-content/sorter@2x.png)
         skin/classic/aero/browser/keyhole-forward-mask.svg
         skin/classic/aero/browser/KUI-background.png
         skin/classic/aero/browser/livemark-folder.png                (livemark-folder-aero.png)
         skin/classic/aero/browser/menu-back.png                      (menu-back-aero.png)
         skin/classic/aero/browser/menu-forward.png                   (menu-forward-aero.png)
         skin/classic/aero/browser/menuPanel.png
         skin/classic/aero/browser/menuPanel-aero.png
         skin/classic/aero/browser/menuPanel-customize.png
--- a/dom/inputmethod/MozKeyboard.js
+++ b/dom/inputmethod/MozKeyboard.js
@@ -447,16 +447,21 @@ MozInputContext.prototype = {
 
     let json = msg.json;
     let resolver = this.takePromiseResolver(json.requestId);
 
     if (!resolver) {
       return;
     }
 
+    // Update context first before resolving promise to avoid race condition
+    if (json.selectioninfo) {
+      this.updateSelectionContext(json.selectioninfo);
+    }
+
     switch (msg.name) {
       case "Keyboard:SendKey:Result:OK":
         resolver.resolve();
         break;
       case "Keyboard:SendKey:Result:Error":
         resolver.reject(json.error);
         break;
       case "Keyboard:GetText:Result:OK":
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -219,16 +219,17 @@ let FormAssistant = {
   textAfterCursor: "",
   scrollIntoViewTimeout: null,
   _focusedElement: null,
   _focusCounter: 0, // up one for every time we focus a new element
   _observer: null,
   _documentEncoder: null,
   _editor: null,
   _editing: false,
+  _selectionPrivate: null,
 
   get focusedElement() {
     if (this._focusedElement && Cu.isDeadWrapper(this._focusedElement))
       this._focusedElement = null;
 
     return this._focusedElement;
   },
 
@@ -239,52 +240,58 @@ let FormAssistant = {
 
   setFocusedElement: function fa_setFocusedElement(element) {
     let self = this;
 
     if (element === this.focusedElement)
       return;
 
     if (this.focusedElement) {
-      this.focusedElement.removeEventListener('mousedown', this);
-      this.focusedElement.removeEventListener('mouseup', this);
       this.focusedElement.removeEventListener('compositionend', this);
       if (this._observer) {
         this._observer.disconnect();
         this._observer = null;
       }
       if (!element) {
         this.focusedElement.blur();
       }
+      if (this._selectionPrivate) {
+        this._selectionPrivate.removeSelectionListener(this);
+        this._selectionPrivate = null;
+      }
     }
 
     this._documentEncoder = null;
     if (this._editor) {
       // When the nsIFrame of the input element is reconstructed by
       // CSS restyling, the editor observers are removed. Catch
       // [nsIEditor.removeEditorObserver] failure exception if that
       // happens.
       try {
         this._editor.removeEditorObserver(this);
       } catch (e) {}
       this._editor = null;
     }
 
     if (element) {
-      element.addEventListener('mousedown', this);
-      element.addEventListener('mouseup', this);
       element.addEventListener('compositionend', this);
       if (isContentEditable(element)) {
         this._documentEncoder = getDocumentEncoder(element);
       }
       this._editor = getPlaintextEditor(element);
       if (this._editor) {
         // Add a nsIEditorObserver to monitor the text content of the focused
         // element.
         this._editor.addEditorObserver(this);
+
+        let selection = this._editor.selection;
+        if (selection) {
+          this._selectionPrivate = selection.QueryInterface(Ci.nsISelectionPrivate);
+          this._selectionPrivate.addSelectionListener(this);
+        }
       }
 
       // If our focusedElement is removed from DOM we want to handle it properly
       let MutationObserver = element.ownerDocument.defaultView.MutationObserver;
       this._observer = new MutationObserver(function(mutations) {
         var del = [].some.call(mutations, function(m) {
           return [].some.call(m.removedNodes, function(n) {
             return n.contains(element);
@@ -300,16 +307,20 @@ let FormAssistant = {
         childList: true,
         subtree: true
       });
     }
 
     this.focusedElement = element;
   },
 
+  notifySelectionChanged: function(aDocument, aSelection, aReason) {
+    this.updateSelection();
+  },
+
   get documentEncoder() {
     return this._documentEncoder;
   },
 
   // Get the nsIPlaintextEditor object of current input field.
   get editor() {
     return this._editor;
   },
@@ -371,42 +382,16 @@ let FormAssistant = {
       case "submit":
         if (this.focusedElement) {
           this.hideKeyboard();
           this.selectionStart = -1;
           this.selectionEnd = -1;
         }
         break;
 
-      case 'mousedown':
-         if (!this.focusedElement) {
-          break;
-        }
-
-        // We only listen for this event on the currently focused element.
-        // When the mouse goes down, note the cursor/selection position
-        this.updateSelection();
-        break;
-
-      case 'mouseup':
-        if (!this.focusedElement) {
-          break;
-        }
-
-        // We only listen for this event on the currently focused element.
-        // When the mouse goes up, see if the cursor has moved (or the
-        // selection changed) since the mouse went down. If it has, we
-        // need to tell the keyboard about it
-        range = getSelectionRange(this.focusedElement);
-        if (range[0] !== this.selectionStart ||
-            range[1] !== this.selectionEnd) {
-          this.updateSelection();
-        }
-        break;
-
       case "resize":
         if (!this.isKeyboardOpened)
           return;
 
         if (this.scrollIntoViewTimeout) {
           content.clearTimeout(this.scrollIntoViewTimeout);
           this.scrollIntoViewTimeout = null;
         }
@@ -418,44 +403,30 @@ let FormAssistant = {
             this.scrollIntoViewTimeout = null;
             if (this.focusedElement && !FormVisibility.isVisible(this.focusedElement)) {
               scrollSelectionOrElementIntoView(this.focusedElement);
             }
           }.bind(this), RESIZE_SCROLL_DELAY);
         }
         break;
 
-      case "input":
-        if (this.focusedElement) {
-          // When the text content changes, notify the keyboard
-          this.updateSelection();
-        }
-        break;
-
       case "keydown":
         if (!this.focusedElement) {
           break;
         }
 
         CompositionManager.endComposition('');
-
-        // We use 'setTimeout' to wait until the input element accomplishes the
-        // change in selection range.
-        content.setTimeout(function() {
-          this.updateSelection();
-        }.bind(this), 0);
         break;
 
       case "keyup":
         if (!this.focusedElement) {
           break;
         }
 
         CompositionManager.endComposition('');
-
         break;
 
       case "compositionend":
         if (!this.focusedElement) {
           break;
         }
 
         CompositionManager.onCompositionEnd();
@@ -521,17 +492,18 @@ let FormAssistant = {
           domWindowUtils.sendKeyEvent('keyup', json.keyCode,
                                       json.charCode, json.modifiers, flags);
         }
 
         this._editing = false;
 
         if (json.requestId && doKeypress) {
           sendAsyncMessage("Forms:SendKey:Result:OK", {
-            requestId: json.requestId
+            requestId: json.requestId,
+            selectioninfo: this.getSelectionInfo()
           });
         }
         else if (json.requestId && !doKeypress) {
           sendAsyncMessage("Forms:SendKey:Result:Error", {
             requestId: json.requestId,
             error: "Keydown event got canceled"
           });
         }
@@ -579,18 +551,16 @@ let FormAssistant = {
             sendAsyncMessage("Forms:SetSelectionRange:Result:Error", {
               requestId: json.requestId,
               error: "failed"
             });
           }
           break;
         }
 
-        this.updateSelection();
-
         if (json.requestId) {
           sendAsyncMessage("Forms:SetSelectionRange:Result:OK", {
             requestId: json.requestId,
             selectioninfo: this.getSelectionInfo()
           });
         }
         break;
       }
@@ -647,24 +617,26 @@ let FormAssistant = {
         break;
       }
 
       case "Forms:SetComposition": {
         CompositionManager.setComposition(target, json.text, json.cursor,
                                           json.clauses);
         sendAsyncMessage("Forms:SetComposition:Result:OK", {
           requestId: json.requestId,
+          selectioninfo: this.getSelectionInfo()
         });
         break;
       }
 
       case "Forms:EndComposition": {
         CompositionManager.endComposition(json.text);
         sendAsyncMessage("Forms:EndComposition:Result:OK", {
           requestId: json.requestId,
+          selectioninfo: this.getSelectionInfo()
         });
         break;
       }
     }
     this._editing = false;
 
   },
 
@@ -753,25 +725,39 @@ let FormAssistant = {
       selectionStart: range[0],
       selectionEnd: range[1],
       textBeforeCursor: textAround.before,
       textAfterCursor: textAround.after,
       changed: changed
     };
   },
 
+  _selectionTimeout: null,
+
   // Notify when the selection range changes
   updateSelection: function fa_updateSelection() {
-    if (!this.focusedElement) {
-      return;
+    // A call to setSelectionRange on input field causes 2 selection changes
+    // one to [0,0] and one to actual value. Both are sent in same tick.
+    // Prevent firing two events in that scenario, always only use the last 1.
+    //
+    // It is also a workaround for Bug 1053048, which prevents 
+    // getSelectionInfo() accessing selectionStart or selectionEnd in the
+    // callback function of nsISelectionListener::NotifySelectionChanged().
+    if (this._selectionTimeout) {
+      content.clearTimeout(this._selectionTimeout);
     }
-    let selectionInfo = this.getSelectionInfo();
-    if (selectionInfo.changed) {
-      sendAsyncMessage("Forms:SelectionChange", this.getSelectionInfo());
-    }
+    this._selectionTimeout = content.setTimeout(function() {
+      if (!this.focusedElement) {
+        return;
+      }
+      let selectionInfo = this.getSelectionInfo();
+      if (selectionInfo.changed) {
+        sendAsyncMessage("Forms:SelectionChange", selectionInfo);
+      }
+    }.bind(this), 0);
   }
 };
 
 FormAssistant.init();
 
 function isContentEditable(element) {
   if (!element) {
     return false;
--- a/dom/inputmethod/mochitest/mochitest.ini
+++ b/dom/inputmethod/mochitest/mochitest.ini
@@ -10,11 +10,12 @@ support-files =
   file_test_sms_app.html
 
 [test_basic.html]
 [test_bug944397.html]
 [test_bug949059.html]
 [test_bug953044.html]
 [test_bug960946.html]
 [test_bug978918.html]
+[test_bug1026997.html]
 [test_bug1043828.html]
 [test_delete_focused_element.html]
 [test_sendkey_cancel.html]
new file mode 100644
--- /dev/null
+++ b/dom/inputmethod/mochitest/test_bug1026997.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1026997
+-->
+<head>
+  <title>SelectionChange on InputMethod API.</title>
+  <script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1026997">Mozilla Bug 1026997</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+inputmethod_setup(function() {
+  runTest();
+});
+
+// The frame script running in file_test_app.html.
+function appFrameScript() {
+  let input = content.document.getElementById('test-input');
+
+  input.focus();
+
+  function next(start, end) {
+    input.setSelectionRange(start, end);
+  }
+
+  addMessageListener("test:KeyBoard:nextSelection", function(event) {
+    let json = event.json;
+    next(json[0], json[1]);
+  });
+}
+
+function runTest() {
+  let actions = [
+    [0, 4],
+    [1, 1],
+    [3, 3],
+    [2, 3]
+  ];
+
+  let counter = 0;
+  let mm = null;
+  let ic = null;
+
+  let im = navigator.mozInputMethod;
+  im.oninputcontextchange = function() {
+    ok(true, 'inputcontextchange event was fired.');
+    im.oninputcontextchange = null;
+
+    ic = im.inputcontext;
+    if (!ic) {
+      ok(false, 'Should have a non-null inputcontext.');
+      inputmethod_cleanup();
+      return;
+    }
+
+    ic.onselectionchange = function() {
+      is(ic.selectionStart, actions[counter][0], "start");
+      is(ic.selectionEnd, actions[counter][1], "end");
+
+      if (++counter === actions.length) {
+        inputmethod_cleanup();
+        return;
+      }
+
+      next();
+    };
+
+    next();
+  };
+
+  // Set current page as an input method.
+  SpecialPowers.wrap(im).setActive(true);
+
+  // Create an app frame to recieve keyboard inputs.
+  let app = document.createElement('iframe');
+  app.src = 'file_test_app.html';
+  app.setAttribute('mozbrowser', true);
+  document.body.appendChild(app);
+  app.addEventListener('mozbrowserloadend', function() {
+    mm = SpecialPowers.getBrowserFrameMessageManager(app);
+    mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
+    next();
+  });
+
+  function next() {
+    if (ic && mm) {
+      mm.sendAsyncMessage('test:KeyBoard:nextSelection', actions[counter]);
+    }
+  }
+}
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -231,19 +231,26 @@ SystemMessageInternal.prototype = {
     }
 
     // Give this message an ID so that we can identify the message and
     // clean it up from the pending message queue when apps receive it.
     let messageID = gUUIDGenerator.generateUUID().toString();
 
     debug("Broadcasting " + aType + " " + JSON.stringify(aMessage) +
       '; extra = ' + JSON.stringify(aExtra));
+
+    let shouldDispatchFunc = this._getMessageConfigurator(aType).shouldDispatch;
+
     // Find pages that registered an handler for this type.
     this._pages.forEach(function(aPage) {
-      if (aPage.type == aType) {
+      if (aPage.type !== aType) {
+        return;
+      }
+
+      let doDispatch = () => {
         let result = this._sendMessageCommon(aType,
                                              aMessage,
                                              messageID,
                                              aPage.pageURL,
                                              aPage.manifestURL,
                                              aExtra);
         debug("Returned status of sending message: " + result);
 
@@ -253,17 +260,32 @@ SystemMessageInternal.prototype = {
         if (result === MSG_SENT_FAILURE_PERM_DENIED) {
           return;
         }
 
         // Queue this message in the corresponding pages.
         this._queueMessage(aPage, aMessage, messageID);
 
         this._openAppPage(aPage, aMessage, aExtra, result);
+      };
+
+      if ('function' !== typeof shouldDispatchFunc) {
+        // If the configurator has no 'shouldDispatch' defined,
+        // always dispatch this message.
+        doDispatch();
+        return;
       }
+
+      shouldDispatchFunc(aPage.manifestURL, aPage.pageURL, aType, aMessage, aExtra)
+        .then(aShouldDispatch => {
+          if (aShouldDispatch) {
+            doDispatch();
+          }
+        });
+
     }, this);
   },
 
   registerPage: function(aType, aPageURI, aManifestURI) {
     if (!aPageURI || !aManifestURI) {
       throw Cr.NS_ERROR_INVALID_ARG;
     }
 
--- a/dom/messages/interfaces/nsISystemMessagesInternal.idl
+++ b/dom/messages/interfaces/nsISystemMessagesInternal.idl
@@ -51,17 +51,26 @@ interface nsISystemMessagesWrapper: nsIS
    */
   jsval wrapMessage(in jsval message, in nsIDOMWindow window);
 };
 
 /*
  * Implements an interface to allow specific message types to
  * configure some behaviors
  */
-[scriptable, uuid(a0e970f6-faa9-4605-89d6-fafae8b10a80)]
+[scriptable, uuid(31b78730-21c6-11e4-8c21-0800200c9a66)]
 interface nsISystemMessagesConfigurator: nsISupports
 {
   /*
    * Will be true if this type of system messages assumes/requires
    * that the app will be brought to the front always.
    */
   readonly attribute boolean mustShowRunningApp;
+
+  /*
+   * A broadcast filter for a specific message type.
+   *
+   * @return Promise which resolves with |true| or |false| to indicate if
+   *         we want to dispatch this message.
+   */
+  jsval shouldDispatch(in DOMString manifestURL, in DOMString pageURL,
+                       in DOMString type, in jsval message, [optional] in jsval extra);
 };
--- a/dom/plugins/base/nsIPluginTag.idl
+++ b/dom/plugins/base/nsIPluginTag.idl
@@ -1,16 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(0e56f04d-cda4-4a55-ab83-e5e29ddd370e)]
+[scriptable, uuid(231df043-3a32-43c4-aaac-7ad2da81e84f)]
 interface nsIPluginTag : nsISupports
 {
   // enabledState is stored as one of the following as an integer in prefs,
   // so if new states are added, they must not renumber the existing states.
   const unsigned long STATE_DISABLED = 0;
   const unsigned long STATE_CLICKTOPLAY = 1;
   const unsigned long STATE_ENABLED = 2;
 
@@ -20,16 +20,21 @@ interface nsIPluginTag : nsISupports
   readonly attribute AUTF8String version;
   readonly attribute AUTF8String name;
 
   /**
    * true only if this plugin is "hardblocked" and cannot be enabled.
    */
   readonly attribute boolean blocklisted;
 
+  /**
+   * true if the state is non-default and locked, false otherwise.
+   */
+  readonly attribute boolean isEnabledStateLocked;
+
   readonly attribute boolean disabled;
   readonly attribute boolean clicktoplay;
            attribute unsigned long enabledState;
 
   readonly attribute PRTime lastModifiedTime;
 
   void getMimeTypes([optional] out unsigned long aCount,
                     [retval, array, size_is(aCount)] out wstring aResults);
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -11,16 +11,17 @@
 #include "nsPluginsDir.h"
 #include "nsPluginHost.h"
 #include "nsIBlocklistService.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsIPlatformCharset.h"
 #include "nsPluginLogging.h"
 #include "nsNPAPIPlugin.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/unused.h"
 #include <cctype>
 #include "mozilla/dom/EncodingUtils.h"
 
 using mozilla::dom::EncodingUtils;
 using namespace mozilla;
 
 // These legacy flags are used in the plugin registry. The states are now
 // stored in prefs, but we still need to be able to import them.
@@ -335,16 +336,32 @@ nsPluginTag::IsBlocklisted()
 
 NS_IMETHODIMP
 nsPluginTag::GetBlocklisted(bool* aBlocklisted)
 {
   *aBlocklisted = IsBlocklisted();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsPluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked)
+{
+  *aIsEnabledStateLocked = false;
+  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+
+  if (NS_WARN_IF(!prefs)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  unused << prefs->PrefIsLocked(GetStatePrefNameForPlugin(this).get(),
+                                aIsEnabledStateLocked);
+
+  return NS_OK;
+}
+
 bool
 nsPluginTag::IsClicktoplay()
 {
   const PluginState state = GetPluginState();
   return (state == ePluginState_Clicktoplay);
 }
 
 NS_IMETHODIMP
rename from mobile/android/base/home/SuggestClient.java
rename to mobile/android/base/SuggestClient.java
--- a/mobile/android/base/home/SuggestClient.java
+++ b/mobile/android/base/SuggestClient.java
@@ -1,16 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-package org.mozilla.gecko.home;
+package org.mozilla.gecko;
 
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.mozglue.RobocopTarget;
+import org.mozilla.gecko.util.HardwareUtils;
 
 import org.json.JSONArray;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.text.TextUtils;
 import android.util.Log;
@@ -23,17 +25,21 @@ import java.net.URL;
 import java.net.URLEncoder;
 import java.util.ArrayList;
 
 /**
  * Use network-based search suggestions.
  */
 public class SuggestClient {
     private static final String LOGTAG = "GeckoSuggestClient";
-    private static final String USER_AGENT = GeckoAppShell.getGeckoInterface().getDefaultUAString();
+
+    // This should go through GeckoInterface to get the UA, but the search activity
+    // doesn't use a GeckoView yet. Until it does, get the UA directly.
+    private static final String USER_AGENT = HardwareUtils.isTablet() ?
+        AppConstants.USER_AGENT_FENNEC_TABLET : AppConstants.USER_AGENT_FENNEC_MOBILE;
 
     private final Context mContext;
     private final int mTimeout;
 
     // should contain the string "__searchTerms__", which is replaced with the query
     private final String mSuggestTemplate;
 
     // the maximum number of suggestions to return
@@ -107,17 +113,17 @@ public class SuggestClient {
 
             if (json != null) {
                 /*
                  * Sample result:
                  * ["foo",["food network","foothill college","foot locker",...]]
                  */
                 JSONArray results = new JSONArray(json);
                 JSONArray jsonSuggestions = results.getJSONArray(1);
-                
+
                 int added = 0;
                 for (int i = 0; (i < jsonSuggestions.length()) && (added < mMaxResults); i++) {
                     String suggestion = jsonSuggestions.getString(i);
                     if (!suggestion.equalsIgnoreCase(query)) {
                         suggestions.add(suggestion);
                         added++;
                     }
                 }
--- a/mobile/android/base/home/BrowserSearch.java
+++ b/mobile/android/base/home/BrowserSearch.java
@@ -14,16 +14,17 @@ import java.util.Locale;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.SuggestClient;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.URLColumns;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.home.SearchLoader.SearchCursorLoader;
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -297,17 +297,16 @@ gbjar.sources += [
     'home/PinSiteDialog.java',
     'home/ReadingListPanel.java',
     'home/ReadingListRow.java',
     'home/RecentTabsPanel.java',
     'home/SearchEngine.java',
     'home/SearchEngineRow.java',
     'home/SearchLoader.java',
     'home/SimpleCursorLoader.java',
-    'home/SuggestClient.java',
     'home/TabMenuStrip.java',
     'home/TabMenuStripLayout.java',
     'home/TopSitesGridItemView.java',
     'home/TopSitesGridView.java',
     'home/TopSitesPanel.java',
     'home/TopSitesThumbnailView.java',
     'home/TwoLinePageRow.java',
     'InputMethods.java',
@@ -374,16 +373,17 @@ gbjar.sources += [
     'SessionParser.java',
     'SharedPreferencesHelper.java',
     'SiteIdentity.java',
     'SmsManager.java',
     'sqlite/ByteBufferInputStream.java',
     'sqlite/MatrixBlobCursor.java',
     'sqlite/SQLiteBridge.java',
     'sqlite/SQLiteBridgeException.java',
+    'SuggestClient.java',
     'SurfaceBits.java',
     'Tab.java',
     'Tabs.java',
     'tabs/PrivateTabsPanel.java',
     'tabs/RemoteTabsContainerPanel.java',
     'tabs/RemoteTabsList.java',
     'tabs/RemoteTabsPanel.java',
     'tabs/RemoteTabsSetupPanel.java',
--- a/mobile/android/base/resources/layout-large-land-v11/tabs_panel.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/tabs_panel.xml
@@ -41,21 +41,20 @@
                                          gecko:tabs="tabs_normal"/>
 
         <org.mozilla.gecko.tabs.PrivateTabsPanel
                 android:id="@+id/private_tabs_panel"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:visibility="gone"/>
 
-        <org.mozilla.gecko.tabs.RemoteTabsPanel
-                android:id="@+id/remote_tabs"
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:visibility="gone"/>
+        <ViewStub android:id="@+id/remote_tabs_panel_stub"
+                  android:layout="@layout/remote_tabs_panel_view"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"/>
 
     </view>
 
     <RelativeLayout android:id="@+id/tabs_panel_footer"
                     android:layout_width="match_parent"
                     android:layout_height="@dimen/browser_toolbar_height">
 
         <view class="org.mozilla.gecko.tabs.TabsPanel$TabsPanelToolbar"
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/remote_tabs_panel_view.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<org.mozilla.gecko.tabs.RemoteTabsPanel xmlns:android="http://schemas.android.com/apk/res/android"
+                                        android:id="@+id/remote_tabs_panel"
+                                        android:layout_width="match_parent"
+                                        android:layout_height="match_parent"/>
--- a/mobile/android/base/resources/layout/tabs_panel.xml
+++ b/mobile/android/base/resources/layout/tabs_panel.xml
@@ -40,17 +40,16 @@
                                          gecko:tabs="tabs_normal"/>
 
         <org.mozilla.gecko.tabs.PrivateTabsPanel
                 android:id="@+id/private_tabs_panel"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:visibility="gone"/>
 
-        <org.mozilla.gecko.tabs.RemoteTabsPanel
-                android:id="@+id/remote_tabs"
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:visibility="gone"/>
+        <ViewStub android:id="@+id/remote_tabs_panel_stub"
+                  android:layout="@layout/remote_tabs_panel_view"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"/>
 
     </view>
 
 </merge>
--- a/mobile/android/base/tabs/TabsPanel.java
+++ b/mobile/android/base/tabs/TabsPanel.java
@@ -27,16 +27,17 @@ import android.content.res.Resources;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewStub;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 
 public class TabsPanel extends LinearLayout
                        implements GeckoPopupMenu.OnMenuItemClickListener,
@@ -108,43 +109,56 @@ public class TabsPanel extends LinearLay
         LayoutInflater.from(context).inflate(R.layout.tabs_panel, this);
         initialize();
 
         mAppStateListener = new AppStateListener() {
             @Override
             public void onResume() {
                 if (mPanel == mPanelRemote) {
                     // Refresh the remote panel.
-                    mPanelRemote.show();
+                    getRemotePanelView().show();
                 }
             }
 
             @Override
             public void onOrientationChanged() {
                 // Remote panel is already refreshed by chrome refresh.
             }
 
             @Override
             public void onPause() {}
         };
     }
 
+    /**
+     * Initializes views in tabs_panel layout
+     *
+     * @throws IllegalStateException
+     *             mCurrentPanel must have a non-null value
+     */
     private void initialize() {
+        if (mCurrentPanel == null) {
+            throw new IllegalStateException(
+                    "mCurrentPanel cannot be null in order for RemotePanelView to be initialized");
+        }
+
+        if (mCurrentPanel == Panel.REMOTE_TABS) {
+            // Initializes mPanelRemote
+            getRemotePanelView();
+        }
+
         mHeader = (RelativeLayout) findViewById(R.id.tabs_panel_header);
         mTabsContainer = (TabsListContainer) findViewById(R.id.tabs_container);
 
         mPanelNormal = (PanelView) findViewById(R.id.normal_tabs);
         mPanelNormal.setTabsPanel(this);
 
         mPanelPrivate = (PanelView) findViewById(R.id.private_tabs_panel);
         mPanelPrivate.setTabsPanel(this);
 
-        mPanelRemote = (PanelView) findViewById(R.id.remote_tabs);
-        mPanelRemote.setTabsPanel(this);
-
         mFooter = (RelativeLayout) findViewById(R.id.tabs_panel_footer);
 
         mAddTab = (ImageButton) findViewById(R.id.add_tab);
         mAddTab.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
                 TabsPanel.this.addTab();
             }
@@ -411,17 +425,17 @@ public class TabsPanel extends LinearLay
         switch (panelToShow) {
             case NORMAL_TABS:
                 mPanel = mPanelNormal;
                 break;
             case PRIVATE_TABS:
                 mPanel = mPanelPrivate;
                 break;
             case REMOTE_TABS:
-                mPanel = mPanelRemote;
+                mPanel = getRemotePanelView();
                 break;
 
             default:
                 throw new IllegalArgumentException("Unknown panel type " + panelToShow);
         }
         mPanel.show();
 
         if (mCurrentPanel == Panel.REMOTE_TABS) {
@@ -467,16 +481,19 @@ public class TabsPanel extends LinearLay
             mPopupMenu.dismiss();
             dispatchLayoutChange(0, 0);
         }
     }
 
     public void refresh() {
         removeAllViews();
 
+        // The View that mPanelRemote points to is invalidated because the layout is invalidated.
+        // mPanelRemote must be null in order to properly initialize RemotePanelView.
+        mPanelRemote = null;
         LayoutInflater.from(mContext).inflate(R.layout.tabs_panel, this);
         initialize();
 
         if (mVisible)
             show(mCurrentPanel);
     }
 
     public void autoHidePanel() {
@@ -565,9 +582,23 @@ public class TabsPanel extends LinearLay
      */
     public Drawable getIconDrawable(Panel panel) {
         return mTabWidget.getIconDrawable(panel.ordinal());
     }
 
     public void setIconDrawable(Panel panel, int resource) {
         mTabWidget.setIconDrawable(panel.ordinal(), resource);
     }
+
+    /**
+     * Initializes mPanelRemote if necessary and provides getter because you
+     * should probably not access mPanelRemote directly
+     *
+     * @return PanelView
+     */
+    private PanelView getRemotePanelView() {
+        if (mPanelRemote == null) {
+            mPanelRemote = (PanelView) ((ViewStub) findViewById(R.id.remote_tabs_panel_stub)).inflate();
+            mPanelRemote.setTabsPanel(TabsPanel.this);
+        }
+        return mPanelRemote;
+    }
 }
--- a/mobile/android/base/tests/testSearchSuggestions.java
+++ b/mobile/android/base/tests/testSearchSuggestions.java
@@ -1,17 +1,17 @@
 package org.mozilla.gecko.tests;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 
 import org.mozilla.gecko.Actions;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.SuggestClient;
 import org.mozilla.gecko.home.BrowserSearch;
-import org.mozilla.gecko.home.SuggestClient;
 
 import android.app.Activity;
 import android.support.v4.app.Fragment;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
 /**
new file mode 100644
index 0000000000000000000000000000000000000000..ef76eb342035c74cec6b6426231a9a75eded0a47
GIT binary patch
literal 4381
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
Xqq;F^(s`ka00000NkvXXu0mjfX4dV}
new file mode 100644
index 0000000000000000000000000000000000000000..ef76eb342035c74cec6b6426231a9a75eded0a47
GIT binary patch
literal 4381
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
Xqq;F^(s`ka00000NkvXXu0mjfX4dV}
new file mode 100644
index 0000000000000000000000000000000000000000..d759d069f1d572bf6f609ea5e9d006834ba001dc
GIT binary patch
literal 3131
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
V%ji#j@%;b*002ovPDHLkV1oQwpeX<V
new file mode 100644
index 0000000000000000000000000000000000000000..f13d3fa5d395f516a88f49424d96421b403cb371
GIT binary patch
literal 2115
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
new file mode 100644
index 0000000000000000000000000000000000000000..ef76eb342035c74cec6b6426231a9a75eded0a47
GIT binary patch
literal 4381
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
Xqq;F^(s`ka00000NkvXXu0mjfX4dV}
new file mode 100644
index 0000000000000000000000000000000000000000..c93181cbf7771b45fbb89e2cb3601c2b63698db5
GIT binary patch
literal 7209
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
new file mode 100644
index 0000000000000000000000000000000000000000..ef76eb342035c74cec6b6426231a9a75eded0a47
GIT binary patch
literal 4381
zc$@(p5#sKNP)<h;3K|Lk000e1NJLTq002q=002!00{{R3HVXp#00004XF*Lt006O%
z3;baP00001b5ch_0Itp)=>Px%`cO<%MF0Q*00s*H2MquL2><{900000001^7D*yrn
z0000000sa92M8WP#P9YPB2xeZ1px~c00RR61_}TW9u*@}G?B;<BvM6pp@Y)(6(v<9
zYM&P(QGw3!3?WUN-}->i^%W#j016ThFJgky^%N{$e9iIz6DD@f^>DS`5hPQH)%6f6
zU3bm$XuannL~;i%W*k0jBuRU9$nP&<l09;sBT#@ogR>DOPy!b%Oq<C{m&Je6_e-A6
z6eCk@!Rc+n>nm}mM1`~}Vv{CWj76BqHiNbqF=2eq^Lo(sQK!~y#_v*gq!ch+9w1K{
z8b%lxMIRzj9U)C0B~cq4N+Bp!9Uo2>AWj}2P#Ygh3qX1jG-)0qPaq{!5++s+J#`90
ze;OP}6eLp@DOw{dRt=QR5I1cRjK>Z-aRpeJ3SOTFTbvpvSQ{l(8+^J0qSz5;rW${}
z0a20%M}!qGV*^!|BrRDOZmtEN)dWtB85>6qEMFCCs~0O?5Gh*?VWJ;)wiblJ6N$we
zB2x~L%LPk`B`;eHE@A?v+Ye-<2%OUkm(Lz~xEO-J79C3#E?^WfW)P0a6^FwnGF=;S
zu@fOt9dol2X{jo)<O!M453Jx9QHLouVHr4R7(H(gU6~j|bpxs093D*)a<39Ua}QLH
zM6ci=u;Ud*do!%y4o-*{uHhXnT_K{`DVx(yw&n<Gs2nq65J-U=UX~J?(iJ*v7gvuE
zF=Q5Go@K@HAb+|HGG-^I+#)(?AX<(jNqAbm>`buX398;jwB>fu`87><Ej(rmHEJ!R
z*%_bK7fXO_%k~+0wID)qCWXIPyXi7UZ#}W&GPCAVx#%Kdm^-K2DvQMz8%QldY8Mtm
zI#+-gmd+ebf)OuaD^q|9IBp>_U=Vk;8>ieCkjWvN(i(}yG?mRqq0<n4y8~gNLScvw
zpw}jErXO>xFLbCNt>GrC;23MBE_<;!gSIz`zcilIDU!<%g}@f0*)m^^U%>50soOrD
z)JATVJDJcC8sGH*002#NQchC<HbW;71PcKO93d};1^O0FD?C}#{>1%GZT{;zv=e3G
zNmzn3n`QGNrz{!Ef9VUV26Zt;f~1>wWv$KcMY6xTK+5UM^zyji!tNZ@BaDD8000eW
zNkl<ZSi_~5cUV*R8pqKJD&hb|tlPHQaclS9d)=FyndFd@Xvjf9304cKhJsQwSW!?@
zt2H6y0zp8A$VP_Lg2+aOYzJc9+q&BOJoo*bld!a{z4v_{(0}sb`+eW<@BN(|2Zsl!
zks}@c-x~YG^jVM2edpbG-+kwuxi3taKJ$M>&YUv$=`Zs0_t&MD-u;EIx8C}E{`9eb
zThElapH=1WZ!Ar?+x**a|2gIE-qLdY>b2|c?jOy6>hEZqIqS`;{JPSFgy!ZOH%^`U
z_1Bh`+S-DGf{oP|&QHDi@f!~;ZS1Vie$KB;PiRQ0s7Omovw{4ptK;J0@{GmB#Z4FA
znEpV@ro8zxQgk?}Fg5k$$&QYmp5ETjP5uDdzGqKfj<M5dEWUX0l_&n%+uWb4_NSL7
zBwadj;?|+8tO)P5TNZ!2HT3l9<HzInoLRcm*O-`?Slra)@%mr5oX$%sO+S2T_fO}}
zo!jtZg!h)kTSGT3_dgyNw`UKq0&^Bw;^QrqoyD)r{4>(5$E)tZ)Y21@PTX3yVdcsV
zKZ2-lw*sm9c-%KYI&)@ej3r2JmS>wSoge&($wviq%@rrJI?ioawru4F@VEF|5Vf)T
z`>((G^1CxjeSLkC4+cdAb>&89TRwdMkB-NqKj-gHhXhm{I+S{1=TGaG@u~#Wn(x2a
z{@v;&OMO?Y+8ci~SE*EnL`9pQdFhWdp$H^2ryeT2ynE+Q|6XrXwKa6P|C%3=C?Ex{
zvgYiyEXr1Td3mX$qVLao0W>upNJs+Gj$Ns@b`C;qM5xtEd;_hO7VA1=w^^>-CY1v0
znHTR9C*-c7q2WYoYT=H{Cv67rLG3*lF7GV%D5;57N~Mufuasy0Ih6F&<IwSj1C5Z&
ziiQf_p@7=bZ;(fYhX;j3x0lp(M=K*Ej~tN(KQ|;_W1p@9cj=7>QUR5gwqw_ByTL)I
zrB<JP@~*CsV5L$WouQT<(dne>mxs3ePUC?C2X<U8EKE&HOR}ScgrWiRD2ReJ*>gdn
z83qV#5B8(PVzD&ku|Xk!JiqZkL(+~NI}RtM-8g(0P-ub>b|ImVg|8tC5QP=1)_t{b
zp&6mneqJokn*96#d!JU-*+_>Ql9CW<P^|ogSn;V^2Pn@4X7lEZjEod1Ly0j=`tZQ%
z-AM<;C4_=bUEU>#>TlJ?AHL^f6)1@ET;Q`v9uTZfImQqMk}=Kx$AF$U9!M&@d}$Z>
zt4OQpYr6deZtNQ%kMcyQ&4AJ<w5oDarKer`MePSt;iXHvc7aC#p{x%$f&P81vZ0VD
zK>2B8T9#tlIC`30)~8kJ4Hc<{CvKhCg=+Us+o|bW3u}H5S``?WoV?18ib5z{Pf?tn
zl|5`vCx}Wt1beP<HxvR1B-AO}Sr+{H8gqRr6ZZ<Oic<T9Nkj@QClN9Dq)|eqsu~ku
z85}xvVkasdB#^)!619;Rwc6J=CmymM-I?g)Bj;O1>-DsO)8jHu_O{UU{JQ3}Ls{q6
z0|S2Gmz`uApG{PtRlW~U*(KeHwpQs$eXEvLF|i{2Rl#3fUGvGTtgQ7=w-9I9N;?VJ
zvv<mB?OYU&R7EMX1%G;`jch+lU^+r1oAfMN!d2-BH%^{ITXWg64!|JL01`hw5M?!1
z%H`ofK>;C3<z|#BKLdslWqPp~V`U;4Iz4mq6H3!gZa|2YSvS2GM+l&`i~C7@JeRIm
zk-RrIC}=aFyrPglT8!yg433UMB*Gs?t*T2v{(gjtxOw_!XjVjox9!H_Nsvx{6+@<0
zty|a?5P;6#wr$5!!f+G8AQDE4M6xI0;`<`KIqhWDTJMO6p3|pKf7{{BgZfE=J&0%E
zs^o=VRhC4BD7|2V9!rr)OzmPs!U&e4Cq3^l{Z46fT1P~O_gZi7o}RVfj0X)M*_Qe`
zOLmuhVP!WjN*bx9WwBg4_|vh_cdZEmKjqHd8)+ThJvSF`5o$34g)ZN;yq|=QOrS9+
zJltG)`}Q`Tq-j;)S`){DDjmj9oI&!K!>s*xZ~WTPar5};P%s4)5VUpq6@LKrkx-*n
zB<I5Ty1S#I)Lvd1ji#)uo+ed<m@i#94IzDD|1YP0?djRHyrp+}-0|M6q5l4HSMu`w
z1xe5+8);Q?E-ZDA=-`YLFE6Q-piT88hN)2BF-%()i$CHpzwWnFEj^2SxAxZl@a6XH
z)p4uyVq)?xY+S=j5=dwxtokZ9q~>->hL?I9_=`NkU^-4ER>2y@7!_;6Ar12ze{*l?
zg$Qjb`0mRq-z|wjb%6&BB*F4b%r1$KF3LdTi#(#k#27(~RiI4FP#CF&<uE_}KP|Pr
zTQ?Q>7p%DwlLwMwtmn@U1o4{C^31lxtCcC>4n#qNC>6oAag2hbFfpY7RWFpDYN-wF
zt-f&m`o`-Qr=CCGl-YER2lYwfNwB6Y3*yyY+lst^q(ga9={QoaHxSS+0>yn+>8aX+
zP1UROu3lSn{aRDz#mt<{Ye*3S*+}bn60E8CB52gHNGT$zC}>pq*;rZy|Hnnp_9=JW
zYhh?hV)8PtUb~o?nVFoNoO#6#8cbRwkA{{@TRAi~ol46x<?R&M6Ekq0-*$NF7x&ug
z;{|!X*372NOykt1<h@Wa$eZ09f5{*cppHo+kNs}a5h@i&sjxN^sY0<rhww3nnQyrl
zRL339vs#mLa*R1m#m2o0Jrg~10%IWI_BPo`n**X!wC!c}oR*?gVjYEPNt6b?LL`HO
zGxl>Hb;SzCK#u3aN+Vq5@jgcr?UDwO)PAjH+E$`XjGC>(NCq0km?RQ>5<GstajF14
zu*O)8@Cm2|iIvdbg9rEJ2wmc@(0-C84A&Z1MvU=GfrJ5&q+Uj&CFAhAfI2f3eFDno
zsE<#)&%S-(#(qht<A?<NE=(rU69l8<&z_1<VFXD_I4ysDJ>d?hCELHb=*e@A9tA-b
zOL(}&Dkwtc1X8e?C&lUw7{`+^G(KD;ktjst_{W)#YA<}bG;?Z`CvXnN9|S$&@@`lt
z#Q?HN0&{&NkwnX39G?L(MUi@mNJJ>`N&M5y>j-6CxOc%(!0Zc`mvqa6vdy{O#hwDl
z)+ReiBvG&!B^YcguUAMUGL}*ZPYq9ed?7C;*|QS_g`?ZaTqEzwt%>&NJZJ|EB8hNT
zhw)1t6Kl)#u@c<Csm9qJ*Iv1r7h{dDOgy+R2vu%K5NxJykN6t%0vjkGm?w#NO&o<`
zEP*xy#~NVgaU`XfZ2Knm{?(~5IoXMci*gaED<A|)S>kcK#>|5RN${*8;!zyihA|||
z5D-!^Q!m3AQWExv{cFT~=QDFGx$*I^C+(F{^80Oz9fTys!e?>B(rfAR_A;HYim7sg
zK}897GhZ(O%Gi}{$?XC;!Ej{;M`bA0MeXLzHgA3!G<_W}OGGLZW#x=5q9)K68`l2>
zIr6=!IYvvAIlC)FsfMRtb%qk|6?IW-lnoRnlaZK?AqAF1W)MWN1})o0-~&WCIJ`Ku
z*jQO2x0pi&61t$gq$wI{1`on<1xb)BA+w=4gN_wbVwTahVUYE{PVx0}lQGdJ+Z<hk
zt|qv~VZ)*C9kkTXFAPTn5^UK>;82e-48f6NjH4+D{^X!9($9WSTp2G9C@CpQf#r=j
zXoE{>13@cr8$lwnm&9NwH?idkf-uBVvi|2|o5c@1E!k0J9v(%0ky2?GVBiZ3MV_s1
zHECl-LrbPOYtS1+G~$nYWa#&$M~V~80YzmsMJXB$2x5*f48_#{&KVT<l0>nzN4-gc
zgWlLMm!Tv_hnG8RqEm`AMaMJ@OVc#PvMfQjo~@S+<p4s`epdJkvG|kE4|(M<a+K4E
z=SreeQo?9$kw%5VMTzlMf0mXECMjr=Y&D?HNq{<Iywj+WLr^2eJ3m*G;U^QZ6cI^@
zZAG!|ihf&g=5T@~bfjL(lSE;Y9~wVm2+DEPh|v#?d9LP|MuIC;G=X*qMPLL)oBEAu
zX$;*j46VYrSk$Pn$-|sSkGNMApxj<9LM(#h82(s52nl_kKU|A$Jet3*C>oJw3?K8*
z{ZQkb$G8o5`6NRFpJ8aYb1}BH+&~ZLdOh5F40KV2sc2e)k9&2v+ZgA2dgb8g1hR$=
zpYYnhG87W{`z&WNv5@cqxr7I67>0@@X#xTjHrr*+@L@=l<IwjNj!xr8y8>(8lb`sB
zaGE1=2=l<n(InG`VI)rA3Ygru8S^F#ALcrGgp=dF?>_9hCcZY=Pl1ydfpdLl29*}P
z5qgnACK2IblUycF;59ip-ser$NHj&~F$m@|c^oc^Wd<HQ=sGM16G{fI5kRia_i;BM
zr!Yre*^Fs$3oEpW!TCgjrcHL42wg(6yQkwrVa~3@+=kDY=rUvWI9LlZ`v_$?9)>vc
z<_ve^75y2=ZgV`)#td_Fn=sF1#^l-4#_=_6_M{mu^Cq~tfgb14ka5Qcc-;pyCxm;*
z)pZOI=S-LgHDL}gTwPsxjMD>g>~DGj=QIL<d^rpM0Az#{!u;)*wj%-PIBGyS{yF5o
Xqq;F^(s`ka00000NkvXXu0mjfX4dV}
new file mode 100644
index 0000000000000000000000000000000000000000..ef76eb342035c74cec6b6426231a9a75eded0a47
GIT binary patch
literal 4381
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
Xqq;F^(s`ka00000NkvXXu0mjfX4dV}
deleted file mode 100644
--- a/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestClient.java
+++ /dev/null
@@ -1,145 +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/. */
-
-package org.mozilla.search.autocomplete;
-
-import org.json.JSONArray;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-
-/**
- * Use network-based search suggestions.
- */
-public class SuggestClient {
-    private static final String LOGTAG = "GeckoSuggestClient";
-    private static final String USER_AGENT = "";
-
-    private final Context mContext;
-    private final int mTimeout;
-
-    // should contain the string "__searchTerms__", which is replaced with the query
-    private final String mSuggestTemplate;
-
-    // the maximum number of suggestions to return
-    private final int mMaxResults;
-
-    // used by robocop for testing
-    private boolean mCheckNetwork;
-
-    // used to make suggestions appear instantly after opt-in
-    private String mPrevQuery;
-    private ArrayList<String> mPrevResults;
-
-    public SuggestClient(Context context, String suggestTemplate, int timeout, int maxResults) {
-        mContext = context;
-        mMaxResults = maxResults;
-        mSuggestTemplate = suggestTemplate;
-        mTimeout = timeout;
-        mCheckNetwork = true;
-    }
-
-    /**
-     * Queries for a given search term and returns an ArrayList of suggestions.
-     */
-    public ArrayList<String> query(String query) {
-        if (query.equals(mPrevQuery))
-            return mPrevResults;
-
-        ArrayList<String> suggestions = new ArrayList<String>();
-        if (TextUtils.isEmpty(mSuggestTemplate) || TextUtils.isEmpty(query)) {
-            return suggestions;
-        }
-
-        if (!isNetworkConnected() && mCheckNetwork) {
-            Log.i(LOGTAG, "Not connected to network");
-            return suggestions;
-        }
-
-        try {
-            String encoded = URLEncoder.encode(query, "UTF-8");
-            String suggestUri = mSuggestTemplate.replace("__searchTerms__", encoded);
-
-            URL url = new URL(suggestUri);
-            String json = null;
-            HttpURLConnection urlConnection = null;
-            InputStream in = null;
-            try {
-                urlConnection = (HttpURLConnection) url.openConnection();
-                urlConnection.setConnectTimeout(mTimeout);
-                urlConnection.setRequestProperty("User-Agent", USER_AGENT);
-                in = new BufferedInputStream(urlConnection.getInputStream());
-                json = convertStreamToString(in);
-            } finally {
-                if (urlConnection != null)
-                    urlConnection.disconnect();
-                if (in != null) {
-                    try {
-                        in.close();
-                    } catch (IOException e) {
-                        Log.e(LOGTAG, "error", e);
-                    }
-                }
-            }
-
-            if (json != null) {
-                /*
-                 * Sample result:
-                 * ["foo",["food network","foothill college","foot locker",...]]
-                 */
-                JSONArray results = new JSONArray(json);
-                JSONArray jsonSuggestions = results.getJSONArray(1);
-
-                int added = 0;
-                for (int i = 0; (i < jsonSuggestions.length()) && (added < mMaxResults); i++) {
-                    String suggestion = jsonSuggestions.getString(i);
-                    if (!suggestion.equalsIgnoreCase(query)) {
-                        suggestions.add(suggestion);
-                        added++;
-                    }
-                }
-            } else {
-                Log.e(LOGTAG, "Suggestion query failed");
-            }
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error", e);
-        }
-
-        mPrevQuery = query;
-        mPrevResults = suggestions;
-        return suggestions;
-    }
-
-    private boolean isNetworkConnected() {
-        NetworkInfo networkInfo = getActiveNetworkInfo();
-        return networkInfo != null && networkInfo.isConnected();
-    }
-
-    private NetworkInfo getActiveNetworkInfo() {
-        ConnectivityManager connectivity = (ConnectivityManager) mContext
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-        if (connectivity == null)
-            return null;
-        return connectivity.getActiveNetworkInfo();
-    }
-
-    private String convertStreamToString(java.io.InputStream is) {
-        try {
-            return new java.util.Scanner(is).useDelimiter("\\A").next();
-        } catch (java.util.NoSuchElementException e) {
-            return "";
-        }
-    }
-}
--- a/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java
+++ b/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java
@@ -16,16 +16,17 @@ import android.text.SpannableString;
 import android.text.style.ForegroundColorSpan;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.ListView;
 
+import org.mozilla.gecko.SuggestClient;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.search.AcceptsSearchQuery;
 import org.mozilla.search.AcceptsSearchQuery.SuggestionAnimation;
 import org.mozilla.search.Constants;
 import org.mozilla.search.R;
 import org.mozilla.search.providers.SearchEngine;
 import org.mozilla.search.providers.SearchEngineManager;
index fc0c8bb0eef4b3248e886bd9ebef1b6de9109895..a016543610e0485b0b44b6242c4fd2934aacf787
GIT binary patch
literal 397
zc$@)^0doF{P)<h;3K|Lk000e1NJLTq002P%002@50{{R3JZnip00004XF*Lt006O%
z3;baP00001b5ch_0Itp)=>Px#Y*0*8MF0Q*{r&ysp*qUS%KQ8K{QUg>{{H&<`Tzg`
z=bkeE|Nr>-_~xNJ(V$r6qd?)MOx>kZn|Vswqg2M4Skt0h<)ugR^72<kEa#y*yu7@)
zlULQ%)ytq_)6>)S_4VhVH_gq>^Yio9*Vpdu?sX9>R{#J20d!JMQvg8b*k%9#0J2F$
zK~z}7?byi<0wEAZ(LyOiaGvM!|Nl{1ptYA23lsD1lBCX#gn}q%3nPU7J~qyj<ecGn
zo#MO>XR5F;;#+}@VnNDWlCV*%B?Tf04KNU-wYn!k1_XkA5G);82sFf7IO|&BCI+(5
zhX4Tr1PBlyK!5<@hXT>QLeTMTUm-lB;N`+23ag>CYu>ZgQsLC@dJEC~?(o?bX+EBg
rdPPlU%k9^`i4f{!%l|ez|D5&(?O$QhvwD0z00000NkvXXu0mjfke9mf
index 23ce9b782e70187955f674f49682c54afe042615..515a6c91f6b10ac04019e748f64333669ac34b9a
GIT binary patch
literal 259
zc%17D@N?(olHy`uVBq!ia0vp^3P7yI!3-py+OJ#yq*&4&eH|GXHuiJ>Nn{1`8H<D5
zofy`glX(f`*aY~5xB}_t3(Wui{d;qH{PTH6fByXW_U+rRU%!CjzkmOJy3F&$y!f9#
zfByLK<M~3%&!0a(UhcnjQrz3OZx78&?~cxH02x{m<QL4~@a#q!kQ3qQ;uvCa`t21@
zz6Jvhhd`IWf>nqAzSr8p_D!YMGyLytHCBehdMi@D$$qo5?GSO;lpr3-<mB7@;n(p4
znF_Wq9FHpe{n~%-sD)~r^xj<An&+j?TTO)@iPRVgOPR!JtUe30gTd3)&t;ucLK6Ul
C{cH>X
index 588173d197d6de904d3516727c363ba0e4b8309d..c268cbde56cdf26f2d5db0465039802d0b4ddd02
GIT binary patch
literal 1482
zc%17D@N?(olHy`uVBq!ia0vp^i9lS%!3-p4oIHCHNU@|l`Z_W&Z0zU$lgJ9>GZqKA
zJ29*~C-ahlfypqyC&cyFuU`yc@COVSVBq)f-~ayo12Ud2c7_W+fBqau_V@Sy{ri`J
z6!8E5e`1uujeWYr8NW(`;K-39U%!6+^5qNAgFufwc<^A=s#V{=e+P;Hxj;dP2Z7>1
zUvJyC4afz`?%%)v_3PJ(zD96!ki!H5SeY2|!i|B9M@xO4FSLBLJOCoTp*#4}f{49S
zB7p4MOF_|bY-Tt_>d6upsH>)j@USyM*w5yh0?Efqy`C>Hv(XV_W`>$y6lDe^XH|L>
zL|Qyv?yI7r^6AqjE;feq3lmPyjr#WOo3OAjP{HQSo6F0~fg#pi<PGFrxNu>^h7E@g
zAAYvN`_ZFEmoHxidPh!5@Y%CxZ{NOMw{9KKUqJC|*RBB-zkK=f&6_vx-o1PA;suZk
z45*0{CqjHWWy+M9GiREbngY45uC6^jJqs2rSh#TE^Ld~!c|PBiSyfFG$l6g7<QM#l
zk!kS{O<{(g-`IZ@#JioAN%+pp#>yhd!OO`nBqFQFCH*zlT*`${#Yl}uKtuAXnc}Z7
z)qLj|r+`q06jw0?c}rzcdo6WwUN8L#?<Cn0T`x_W@FjSGXw?D%`|fm)@cXveK7k3D
z(+s};`|O!}=;4u^x6xN^9DjP{UCfN*{%8E{Uqe)8WUt@Gmd|_%{#TB?ck;JPecf-G
z+okqn&bnQ`rw&axk+@s#<f8khlrF}9H;Ik1|Ed}r=JS8`pBcamQ0(dA7?N@C?X9De
zZaav$C2mc+sod%=HnZ}~;WIL6Krqk1*x0!EkxlF_-Q7arn>>BX!@lRlmfCwq|DCgT
z0nbz}zaq11jSNg23JnKB987)(J9Nlf7aiNe7&6PI?#d3ENe_#@Kjjo=W}Fz+Xt>z@
z!;9$+KO!f)+?slBT40>Rr!PT)I%<(CT=Y60O}VUP#H!+LY&hZX+77Q}N^v_oIh8(q
zTdDN(yKBhdwu<YD$~p>9uP}YKb2m&9>F!sR<K9%qY0r4~cjcp<3lkhQcb;QVXgT`n
z*4kvpP506mQ#$?U3rp%f_O?$@F8E<u>z#D4;@62oEDHP|ulBM&U!DG@g@13vg-7}~
z_o#fDb#M8`2d^Yg`BgkV-eh_-K*Fwv1LP+L9K;{{hj!KvyEX45s_psP!8%*Jw0Y)-
zM|0)5qy88fKlIe;WlcZc`gzU1OEzC7t)J!={d?#8oL!~sXLIZ;cyq>6?LhzP*g&Nh
zd5T4k7`Pw4IhrjO{cUw>_KJTm>Rx>h&$S3qFA;Jq+rrVyySx1DV(vBbgzsE@uBphh
zUZO7FH}&$t$I)iF>m@uEc1?YKT{m7VM&?z)OBaVdQ@&J4zs{b`mwzYHw!`Uaw)olD
zD9iOaw_XNs&gN2i?YCc`OD5YQXm`3nYt!uK`jMLpTzB4H{^401^T|mUFWr*Oe!r^Q
zg#TsvS<~Cwrd6&!G|O4Fx$Dj>r$URn54UC5s0OT9zUt29)v8P0%u?EJ>9}Xji|XDb
z&o%{}SZXQEw>wMEsV;u&iB(C*J^%LH2?&|#ULXJLgNfFhX9t|PSOgq?lq(+AtNE)g
X6Z~k8i*U6KD5rb6`njxgN@xNAK^b2C
--- a/mobile/android/search/res/drawable/widget_button_left.xml
+++ b/mobile/android/search/res/drawable/widget_button_left.xml
@@ -1,29 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_pressed="true">
-        <shape android:shape="rectangle">
-            <corners android:topLeftRadius="4dp"
-                     android:topRightRadius="0dp"
-                     android:bottomLeftRadius="0dp"
-                     android:bottomRightRadius="0dp"/>
-            <solid android:color="@color/widget_button_pressed"/>
-        </shape>
-    </item>
+    <item android:state_pressed="true"
+           android:drawable="@drawable/widget_button_left_pressed"/>
 
     <!-- The left button is gray in its off state -->
-    <item>
-        <shape android:shape="rectangle">
-            <corners android:topLeftRadius="4dp"
-                     android:topRightRadius="0dp"
-                     android:bottomLeftRadius="0dp"
-                     android:bottomRightRadius="0dp"/>
-            <solid android:color="@color/widget_logo_highlight"/>
-        </shape>
-    </item>
+    <item android:drawable="@drawable/widget_button_left_default"/>
 
 </selector>
new file mode 100644
--- /dev/null
+++ b/mobile/android/search/res/drawable/widget_button_left_default.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!-- These drawables have to be wrapped in a layer-list in order to produce padding at
+     the bottom of the drawable. That padding ensures the drawable doesn't block the
+     orange strip in widget_bg.9.png -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:bottom="@dimen/widget_bg_border_offset">
+        <shape android:shape="rectangle">
+            <corners android:topLeftRadius="@dimen/widget_drawable_corner_radius"
+                     android:topRightRadius="0dp"
+                     android:bottomLeftRadius="0dp"
+                     android:bottomRightRadius="0dp"/>
+            <solid android:color="@color/widget_logo_default"/>
+        </shape>
+    </item>
+</layer-list>
new file mode 100644
--- /dev/null
+++ b/mobile/android/search/res/drawable/widget_button_left_pressed.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!-- These drawables have to be wrapped in a layer-list in order to produce padding at
+     the bottom of the drawable. That padding ensures the drawable doesn't block the
+     orange strip in widget_bg.9.png -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:bottom="@dimen/widget_bg_border_offset">
+        <shape android:shape="rectangle">
+            <corners android:topLeftRadius="@dimen/widget_drawable_corner_radius"
+                     android:topRightRadius="0dp"
+                     android:bottomLeftRadius="0dp"
+                     android:bottomRightRadius="0dp"/>
+            <solid android:color="@color/widget_button_pressed"/>
+        </shape>
+    </item>
+</layer-list>
--- a/mobile/android/search/res/drawable/widget_button_middle.xml
+++ b/mobile/android/search/res/drawable/widget_button_middle.xml
@@ -1,20 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_pressed="true">
-        <shape android:shape="rectangle">
-            <corners android:topLeftRadius="0dp"
-                     android:topRightRadius="0dp"
-                     android:bottomLeftRadius="0dp"
-                     android:bottomRightRadius="0dp"/>
-            <solid android:color="@color/widget_button_pressed"/>
-        </shape>
-    </item>
+    <item android:state_pressed="true"
+           android:drawable="@drawable/widget_button_middle_pressed"/>
 
     <item android:drawable="@android:color/transparent"/>
 
 </selector>
new file mode 100644
--- /dev/null
+++ b/mobile/android/search/res/drawable/widget_button_middle_pressed.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!-- These drawables have to be wrapped in a layer-list in order to produce padding at
+     the bottom of the drawable. That padding ensures the drawable doesn't block the
+     orange strip in widget_bg.9.png -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:bottom="@dimen/widget_bg_border_offset">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/widget_button_pressed"/>
+        </shape>
+    </item>
+</layer-list>
--- a/mobile/android/search/res/drawable/widget_button_right.xml
+++ b/mobile/android/search/res/drawable/widget_button_right.xml
@@ -1,20 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_pressed="true">
-        <shape android:shape="rectangle">
-            <corners android:topLeftRadius="0dp"
-                     android:topRightRadius="4dp"
-                     android:bottomLeftRadius="0dp"
-                     android:bottomRightRadius="0dp"/>
-            <solid android:color="@color/widget_button_pressed"/>
-        </shape>
-    </item>
+    <item android:state_pressed="true"
+          android:drawable="@drawable/widget_button_right_pressed"/>
 
     <item android:drawable="@android:color/transparent"/>
 
 </selector>
new file mode 100644
--- /dev/null
+++ b/mobile/android/search/res/drawable/widget_button_right_pressed.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!-- These drawables have to be wrapped in a layer-list in order to produce padding at
+     the bottom of the drawable. That padding ensures the drawable doesn't block the
+     orange strip in widget_bg.9.png -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:bottom="@dimen/widget_bg_border_offset">
+        <shape android:shape="rectangle">
+            <corners android:topLeftRadius="0dp"
+                     android:topRightRadius="@dimen/widget_drawable_corner_radius"
+                     android:bottomLeftRadius="0dp"
+                     android:bottomRightRadius="0dp"/>
+            <solid android:color="@color/widget_button_pressed"/>
+        </shape>
+    </item>
+</layer-list>
--- a/mobile/android/search/res/layout/search_widget.xml
+++ b/mobile/android/search/res/layout/search_widget.xml
@@ -10,38 +10,40 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/widget_header_height"
     android:orientation="horizontal"
     android:background="@drawable/widget_bg">
 
     <ImageView android:id="@+id/logo_button"
         android:layout_width="0dp"
         android:layout_weight="1"
+        android:padding="@dimen/widget_padding"
         android:background="@drawable/widget_button_left"
         android:layout_height="match_parent"
-        android:src="@drawable/icon"/>
+        android:src="@drawable/widget_icon"/>
 
     <LinearLayout android:id="@+id/search_button"
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="1"
         android:gravity="center"
         android:contentDescription="@string/search_widget_button_label"
         android:orientation="horizontal"
         android:background="@drawable/widget_button_middle">
 
         <TextView android:id="@+id/search_button_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:drawableLeft="@drawable/ic_widget_search"
-            android:drawablePadding="@dimen/widget_drawable_padding"
+            android:drawablePadding="@dimen/widget_padding"
             android:text="@string/search_widget_button_label"
             android:gravity="center"
+            android:fontFamily="sans-serif"
             android:textSize="@dimen/widget_text_size"
-            android:textColor="@color/text_color_secondary"/>
+            android:textColor="@color/widget_text_color"/>
 
     </LinearLayout>
 
     <LinearLayout android:id="@+id/new_tab_button"
         android:layout_width="0dp"
         android:layout_weight="1"
         android:layout_height="match_parent"
         android:layout_centerVertical="true"
@@ -49,17 +51,18 @@
         android:gravity="center"
         android:orientation="horizontal"
         android:background="@drawable/widget_button_right">
 
         <TextView android:id="@+id/new_tab_button_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:drawableLeft="@drawable/ic_widget_new_tab"
-            android:drawablePadding="@dimen/widget_drawable_padding"
+            android:drawablePadding="@dimen/widget_padding"
             android:gravity="center"
             android:text="@string/new_tab"
+            android:fontFamily="sans-serif"
             android:textSize="@dimen/widget_text_size"
-            android:textColor="@color/text_color_secondary"/>
+            android:textColor="@color/widget_text_color"/>
 
     </LinearLayout>
 
 </LinearLayout>
--- a/mobile/android/search/res/values/search_colors.xml
+++ b/mobile/android/search/res/values/search_colors.xml
@@ -10,13 +10,14 @@
 
     <color name="edit_text_default">#AFB1B3</color>
 
     <!-- card colors -->
     <color name="card_background">#ffffff</color>
     <color name="card_background_pressed">#DCDCE1</color>
     <color name="card_border">#BFBFBF</color>
 
-    <color name="widget_logo_highlight">#11000000</color>
+    <color name="widget_logo_default">#EBEBF0</color>
     <color name="widget_button_pressed">#33000000</color>
+    <color name="widget_text_color">#5F6368</color>
 
     <!-- Search suggestion highlight color is defined in SearchFragment.java -->
 </resources>
--- a/mobile/android/search/res/values/search_dimens.xml
+++ b/mobile/android/search/res/values/search_dimens.xml
@@ -29,12 +29,14 @@
     <dimen name="jump_button_padding_x">15dp</dimen>
 
     <dimen name="search_bar_padding_y">10dp</dimen>
 
     <!-- Widget Buttons -->
     <dimen name="widget_header_height">70dp</dimen>
     <dimen name="widget_button_offset">-50dp</dimen>
     <dimen name="widget_button_padding">45dp</dimen>
-    <dimen name="widget_text_size">13sp</dimen>
-    <dimen name="widget_drawable_padding">4dp</dimen>
+    <dimen name="widget_text_size">14sp</dimen>
+    <dimen name="widget_padding">7dp</dimen>
+    <dimen name="widget_drawable_corner_radius">4dp</dimen>
+    <dimen name="widget_bg_border_offset">3dp</dimen>
 
 </resources>
--- a/mobile/android/search/search_activity_sources.mozbuild
+++ b/mobile/android/search/search_activity_sources.mozbuild
@@ -3,17 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 search_activity_sources = [
     'java/org/mozilla/search/AcceptsSearchQuery.java',
     'java/org/mozilla/search/autocomplete/AutoCompleteAdapter.java',
     'java/org/mozilla/search/autocomplete/ClearableEditText.java',
-    'java/org/mozilla/search/autocomplete/SuggestClient.java',
     'java/org/mozilla/search/autocomplete/SuggestionsFragment.java',
     'java/org/mozilla/search/Constants.java',
     'java/org/mozilla/search/MainActivity.java',
     'java/org/mozilla/search/PostSearchFragment.java',
     'java/org/mozilla/search/PreSearchFragment.java',
     'java/org/mozilla/search/providers/BingSearchEngine.java',
     'java/org/mozilla/search/providers/GoogleSearchEngine.java',
     'java/org/mozilla/search/providers/SearchEngine.java',
--- a/netwerk/protocol/rtsp/rtsp/ASessionDescription.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ASessionDescription.cpp
@@ -326,17 +326,23 @@ bool ASessionDescription::parseNTPRange(
     s = end + 1;  // skip the dash.
 
     if (!strncmp("now", s, 3)) {
         return false;  // no absolute end time available
     }
 
     *npt2 = strtof(s, &end);
 
-    if (end == s || *end != '\0') {
+    if (end == s) {
+        // No end time available. It means to play until the end of the clip.
+        return true;
+    }
+
+    if (*end != '\0') {
+        // Malformed format in NTP description.
         return false;
     }
 
     return *npt2 > *npt1;
 }
 
 }  // namespace android
 
--- a/toolkit/devtools/webconsole/utils.js
+++ b/toolkit/devtools/webconsole/utils.js
@@ -565,31 +565,29 @@ let WebConsoleUtils = {
   },
   /**
    * The inputNode "paste" event handler generator. Helps prevent self-xss attacks
    *
    * @param nsIDOMElement inputField
    * @param nsIDOMElement notificationBox
    * @returns A function to be added as a handler to 'paste' and 'drop' events on the input field
    */
-  pasteHandlerGen: function WCU_pasteHandlerGen(inputField, notificationBox){
+  pasteHandlerGen: function WCU_pasteHandlerGen(inputField, notificationBox, msg, okstring) {
     let handler = function WCU_pasteHandler(aEvent) {
       if (WebConsoleUtils.usageCount >= CONSOLE_ENTRY_THRESHOLD) {
         inputField.removeEventListener("paste", handler);
         inputField.removeEventListener("drop", handler);
         return true;
       }
       if (notificationBox.getNotificationWithValue("selfxss-notification")) {
         aEvent.preventDefault();
         aEvent.stopPropagation();
         return false;
       }
-      let l10n = new WebConsoleUtils.l10n("chrome://browser/locale/devtools/webconsole.properties");
-      let okstring = l10n.getStr("selfxss.okstring");
-      let msg = l10n.getFormatStr("selfxss.msg", [okstring]);
+
 
       let notification = notificationBox.appendNotification(msg,
         "selfxss-notification", null, notificationBox.PRIORITY_WARNING_HIGH, null,
         function(eventType) {
           // Cleanup function if notification is dismissed
           if (eventType == "removed") {
             inputField.removeEventListener("keyup", pasteKeyUpHandler);
           }
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -3101,31 +3101,34 @@ var gDetailView = {
         warning.textContent = gStrings.ext.GetStringFromName("details.notification.openH264Pending");
       } else {
         this.node.removeAttribute("notification");
       }
     }
 
     let menulist = document.getElementById("detail-state-menulist");
     let addonType = AddonManager.addonTypes[this._addon.type];
-    if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE &&
-        (hasPermission(this._addon, "ask_to_activate") ||
-         hasPermission(this._addon, "enable") ||
-         hasPermission(this._addon, "disable"))) {
+    if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) {
       let askItem = document.getElementById("detail-ask-to-activate-menuitem");
       let alwaysItem = document.getElementById("detail-always-activate-menuitem");
       let neverItem = document.getElementById("detail-never-activate-menuitem");
+      let hasActivatePermission =
+        ["ask_to_activate", "enable", "disable"].some(perm => hasPermission(this._addon, perm));
+
       if (this._addon.userDisabled === true) {
         menulist.selectedItem = neverItem;
       } else if (this._addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) {
         menulist.selectedItem = askItem;
       } else {
         menulist.selectedItem = alwaysItem;
       }
+
+      menulist.disabled = !hasActivatePermission;
       menulist.hidden = false;
+      menulist.classList.add('no-auto-hide');
     } else {
       menulist.hidden = true;
     }
 
     this.node.setAttribute("active", this._addon.isActive);
   },
 
   clearLoading: function gDetailView_clearLoading() {
--- a/toolkit/mozapps/extensions/content/extensions.xml
+++ b/toolkit/mozapps/extensions/content/extensions.xml
@@ -1301,36 +1301,36 @@
               this.removeAttribute("notification");
             }
           }
 
           this._preferencesBtn.hidden = (!this.mAddon.optionsURL) ||
                                         this.mAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO;
 
           let addonType = AddonManager.addonTypes[this.mAddon.type];
-          if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE &&
-              (this.hasPermission("ask_to_activate") ||
-               this.hasPermission("enable") ||
-               this.hasPermission("disable"))) {
+          if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) {
             this._enableBtn.disabled = true;
             this._disableBtn.disabled = true;
             this._askToActivateMenuitem.disabled = !this.hasPermission("ask_to_activate");
             this._alwaysActivateMenuitem.disabled = !this.hasPermission("enable");
             this._neverActivateMenuitem.disabled = !this.hasPermission("disable");
             if (this.mAddon.userDisabled === true) {
               this._stateMenulist.selectedItem = this._neverActivateMenuitem;
             } else if (this.mAddon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) {
               this._stateMenulist.selectedItem = this._askToActivateMenuitem;
             } else {
               this._stateMenulist.selectedItem = this._alwaysActivateMenuitem;
             }
-            this._stateMenulist.selectedItem.disabled = false;
-            this._stateMenulist.disabled = false;
+            let hasActivatePermission =
+              ["ask_to_activate", "enable", "disable"].some(perm => this.hasPermission(perm));
+            this._stateMenulist.disabled = !hasActivatePermission;
+            this._stateMenulist.hidden = false;
+            this._stateMenulist.classList.add('no-auto-hide');
           } else {
-            this._stateMenulist.disabled = true;
+            this._stateMenulist.hidden = true;
             if (this.hasPermission("enable")) {
               this._enableBtn.hidden = false;
               let tooltip = gViewController.commands["cmd_enableItem"]
                                            .getTooltip(this.mAddon);
               this._enableBtn.setAttribute("tooltiptext", tooltip);
             } else {
               this._enableBtn.hidden = true;
             }
--- a/toolkit/mozapps/extensions/internal/PluginProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/PluginProvider.jsm
@@ -456,16 +456,19 @@ function PluginWrapper(aId, aName, aDesc
   });
 
   this.__defineGetter__("operationsRequiringRestart", function() {
     return AddonManager.OP_NEEDS_RESTART_NONE;
   });
 
   this.__defineGetter__("permissions", function() {
     let permissions = 0;
+    if (aTags[0].isEnabledStateLocked) {
+      return permissions;
+    }
     if (!this.appDisabled) {
 
       if (this.userDisabled !== true)
         permissions |= AddonManager.PERM_CAN_DISABLE;
 
       let blocklistState = this.blocklistState;
       let isCTPBlocklisted =
         (blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE ||
--- a/toolkit/mozapps/extensions/test/browser/browser-common.ini
+++ b/toolkit/mozapps/extensions/test/browser/browser-common.ini
@@ -39,16 +39,17 @@ skip-if = e10s # Bug ?????? - test times
 [browser_dragdrop.js]
 skip-if = buildapp == 'mulet'
 [browser_experiments.js]
 [browser_list.js]
 [browser_metadataTimeout.js]
 [browser_searching.js]
 [browser_sorting.js]
 [browser_sorting_plugins.js]
+[browser_plugin_enabled_state_locked.js]
 skip-if = e10s # Bug ?????? - leaked until shutdown [nsGlobalWindow #1760 about:blank]
 [browser_uninstalling.js]
 skip-if = e10s # Bug ?????? - leaked until shutdown [nsGlobalWindow #1760 about:blank]
 [browser_install.js]
 [browser_recentupdates.js]
 [browser_manualupdates.js]
 [browser_globalwarnings.js]
 [browser_globalinformations.js]
--- a/toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js
@@ -195,26 +195,26 @@ function part11() {
   });
 }
 
 function part12(aWindow) {
   gManagerWindow = aWindow;
   let pluginEl = get_addon_element(gManagerWindow, gTestPluginId);
   pluginEl.parentNode.ensureElementIsVisible(pluginEl);
   let menu = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "state-menulist");
-  is_element_hidden(menu, "part12: state menu should be hidden");
+  is(menu.disabled, true, "part12: state menu should be disabled");
 
   let details = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
   EventUtils.synthesizeMouseAtCenter(details, {}, gManagerWindow);
   wait_for_view_load(gManagerWindow, part13);
 }
 
 function part13() {
   let menu = gManagerWindow.document.getElementById("detail-state-menulist");
-  is_element_hidden(menu, "part13: detail state menu should be hidden");
+  is(menu.disabled, true, "part13: detail state menu should be disabled");
 
   setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml", function() {
     run_next_test();
   });
 }
 
 function end_test() {
   Services.prefs.clearUserPref("plugins.click_to_play");
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/browser_plugin_enabled_state_locked.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that state menu is displayed correctly (enabled or disabled) in the add-on manager
+// when the preference is unlocked / locked
+const {classes: Cc, interfaces: Ci} = Components;
+const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
+const gIsOSX = ("nsILocalFileMac" in Ci);
+const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
+  ("@mozilla.org/gio-service;1" in Cc);
+
+let gManagerWindow;
+let gCategoryUtilities;
+let gPluginElement;
+
+function getTestPluginPref() {
+  let prefix = "plugin.state.";
+  if (gIsWindows)
+    return prefix + "nptest";
+  else if (gIsLinux)
+    return prefix + "libnptest";
+  else
+    return prefix + "test";
+}
+
+registerCleanupFunction(() => {
+  Services.prefs.unlockPref(getTestPluginPref());
+  Services.prefs.clearUserPref(getTestPluginPref());
+});
+
+function getPlugins() {
+  let deferred = Promise.defer();
+  AddonManager.getAddonsByTypes(["plugin"], plugins => deferred.resolve(plugins));
+  return deferred.promise;
+}
+
+function getTestPlugin(aPlugins) {
+  let testPluginId;
+
+  for (let plugin of aPlugins) {
+    if (plugin.name == "Test Plug-in") {
+      testPluginId = plugin.id;
+      break;
+    }
+  }
+
+  Assert.ok(testPluginId, "Test Plug-in should exist");
+
+  let pluginElement = get_addon_element(gManagerWindow, testPluginId);
+  pluginElement.parentNode.ensureElementIsVisible(pluginElement);
+
+  return pluginElement;
+}
+
+function checkStateMenu(locked) {
+  Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
+    "Preference lock state should be correct.");
+  let menuList = gManagerWindow.document.getAnonymousElementByAttribute(gPluginElement, "anonid", "state-menulist");
+
+  is_element_visible(menuList, "State menu should be visible.");
+  Assert.equal(menuList.disabled, locked,
+    "State menu should" + (locked === true ? "" : " not") + " be disabled.");
+}
+
+function checkStateMenuDetail(locked) {
+  Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
+    "Preference should be " + (locked === true ? "" : "un") + "locked.");
+
+  // open details menu
+  let details = gManagerWindow.document.getAnonymousElementByAttribute(gPluginElement, "anonid", "details-btn");
+  is_element_visible(details, "Details link should be visible.");
+  EventUtils.synthesizeMouseAtCenter(details, {}, gManagerWindow);
+
+  let deferred = Promise.defer();
+  wait_for_view_load(gManagerWindow, function() {
+    let menuList = gManagerWindow.document.getElementById("detail-state-menulist");
+    is_element_visible(menuList, "Details state menu should be visible.");
+    Assert.equal(menuList.disabled, locked,
+      "Details state menu enabled state should be correct.");
+    deferred.resolve();
+  });
+  return deferred.promise;
+}
+
+add_task(function* initializeState() {
+  Services.prefs.setIntPref(getTestPluginPref(), Ci.nsIPluginTag.STATE_ENABLED);
+  Services.prefs.unlockPref(getTestPluginPref());
+  gManagerWindow = yield open_manager();
+  gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+  yield gCategoryUtilities.openType("plugin");
+
+  let plugins = yield getPlugins();
+  gPluginElement = getTestPlugin(plugins);
+});
+
+// Tests that plugin state menu is enabled if the preference is unlocked
+add_task(function* taskCheckStateMenuIsEnabled() {
+  checkStateMenu(false);
+  yield checkStateMenuDetail(false);
+});
+
+// Lock the preference and then reload the plugin category
+add_task(function* reinitializeState() {
+  // lock the preference
+  Services.prefs.lockPref(getTestPluginPref());
+  yield gCategoryUtilities.openType("plugin");
+  // Retrieve the test plugin element
+  let plugins = yield getPlugins();
+  gPluginElement = getTestPlugin(plugins);
+});
+
+// Tests that plugin state menu is disabled if the preference is locked
+add_task(function* taskCheckStateMenuIsDisabled() {
+  checkStateMenu(true);
+  yield checkStateMenuDetail(true);
+});
+
+add_task(function* testCleanup() {
+  yield close_manager(gManagerWindow);
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
@@ -1,15 +1,16 @@
 # The file is shared between the two main xpcshell manifest files.
 [test_AddonRepository.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_AddonRepository_cache.js]
 # Bug 676992: test consistently hangs on Android
-skip-if = os == "android"
+# Bug 1026805: frequent hangs on OSX 10.8
+skip-if = os == "android" || os == "mac"
 run-sequentially = Uses hardcoded ports in xpi files.
 [test_AddonRepository_compatmode.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_LightweightThemeManager.js]
 [test_backgroundupdate.js]
 [test_bad_json.js]
 [test_badschema.js]
@@ -28,34 +29,36 @@ skip-if = os == "android"
 skip-if = os == "android"
 run-sequentially = Uses hardcoded ports in xpi files.
 [test_bug299716_2.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 run-sequentially = Hardcoded port in install.rdf.
 [test_bug324121.js]
 # Bug 676992: test consistently hangs on Android
-skip-if = os == "android"
+# Bug 1026805: frequent hangs on OSX 10.8
+skip-if = os == "android" || os == "mac"
 run-sequentially = Uses hardcoded ports in xpi files.
 [test_bug335238.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 run-sequentially = Uses hardcoded ports in xpi files.
 [test_bug371495.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_bug384052.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_bug393285.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_bug394300.js]
 # Bug 676992: test consistently hangs on Android
-skip-if = os == "android"
+# Bug 1026805: frequent hangs on OSX 10.8
+skip-if = os == "android" || os == "mac"
 run-sequentially = Uses hardcoded ports in xpi files.
 [test_bug397778.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_bug406118.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_bug424262.js]
rename from browser/themes/linux/in-content/common.css
rename to toolkit/themes/linux/global/in-content/common.css
--- a/browser/themes/linux/in-content/common.css
+++ b/toolkit/themes/linux/global/in-content/common.css
@@ -1,13 +1,13 @@
 /* - This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-%include ../../shared/in-content/common.inc.css
+%include ../../../shared/in-content/common.inc.css
 
 xul|tab[selected] {
   /* Override styles for tab[selected] from
      toolkit/themes/linux/global/tabbox.css */
   margin-bottom: 0;
   border-bottom-left-radius: 0;
   border-bottom-right-radius: 0;
 }
--- a/toolkit/themes/linux/global/jar.mn
+++ b/toolkit/themes/linux/global/jar.mn
@@ -49,9 +49,20 @@ toolkit.jar:
 +  skin/classic/global/icons/panelarrow-horizontal.svg         (icons/panelarrow-horizontal.svg)
 +  skin/classic/global/icons/panelarrow-vertical.svg           (icons/panelarrow-vertical.svg)
 +  skin/classic/global/icons/resizer.png                       (icons/resizer.png)
 +  skin/classic/global/icons/sslWarning.png                    (icons/sslWarning.png)
 +  skin/classic/global/icons/wrap.png                          (icons/wrap.png)
 +  skin/classic/global/icons/webapps-16.png                    (icons/webapps-16.png)
 +  skin/classic/global/icons/webapps-64.png                    (icons/webapps-64.png)
    skin/classic/global/menu/shared-menu-check.png              (../../shared/menu-check.png)
+*  skin/classic/global/in-content/common.css                   (in-content/common.css)
+   skin/classic/global/in-content/check.png                    (../../shared/in-content/check.png)
+   skin/classic/global/in-content/check@2x.png                 (../../shared/in-content/check@2x.png)
+   skin/classic/global/in-content/dropdown.png                 (../../shared/in-content/dropdown.png)
+   skin/classic/global/in-content/dropdown@2x.png              (../../shared/in-content/dropdown@2x.png)
+   skin/classic/global/in-content/dropdown-disabled.png        (../../shared/in-content/dropdown-disabled.png)
+   skin/classic/global/in-content/dropdown-disabled@2x.png     (../../shared/in-content/dropdown-disabled@2x.png)
+   skin/classic/global/in-content/help-glyph.png               (../../shared/in-content/help-glyph.png)
+   skin/classic/global/in-content/help-glyph@2x.png            (../../shared/in-content/help-glyph@2x.png)
+   skin/classic/global/in-content/sorter.png                   (../../shared/in-content/sorter.png)
+   skin/classic/global/in-content/sorter@2x.png                (../../shared/in-content/sorter@2x.png)
 +  skin/classic/global/toolbar/spring.png                      (toolbar/spring.png)
--- a/toolkit/themes/linux/mozapps/extensions/extensions.css
+++ b/toolkit/themes/linux/mozapps/extensions/extensions.css
@@ -879,16 +879,20 @@ setting[type="radio"] > radiogroup {
 
 
 /*** buttons ***/
 
 .addon-control[disabled="true"] {
   display: none;
 }
 
+.addon-control.no-auto-hide {
+  display: block;
+}
+
 .addon-control.enable {
   list-style-image: url("moz-icon://stock/gtk-yes?size=button");
 }
 
 .addon-control.disable {
   list-style-image: url("moz-icon://stock/gtk-no?size=button");
 }
 
rename from browser/themes/osx/in-content/common.css
rename to toolkit/themes/osx/global/in-content/common.css
--- a/browser/themes/osx/in-content/common.css
+++ b/toolkit/themes/osx/global/in-content/common.css
@@ -1,13 +1,13 @@
 /* - This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-%include ../../shared/in-content/common.inc.css
+%include ../../../shared/in-content/common.inc.css
 
 xul|tabs {
   padding-right: 0;
   padding-left: 0;
 }
 
 xul|tab[selected] {
   text-shadow: none;
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -179,16 +179,27 @@ toolkit.jar:
   skin/classic/global/media/volume-full.png                          (media/volume-full.png)
   skin/classic/global/media/volume-full@2x.png                       (media/volume-full@2x.png)
   skin/classic/global/media/clicktoplay-bgtexture.png                (media/clicktoplay-bgtexture.png)
   skin/classic/global/media/videoClickToPlayButton.svg               (media/videoClickToPlayButton.svg)
   skin/classic/global/menu/menu-arrow.png                            (menu/menu-arrow.png)
   skin/classic/global/menu/menu-arrow@2x.png                         (menu/menu-arrow@2x.png)
   skin/classic/global/menu/shared-menu-check.png                     (../../shared/menu-check.png)
   skin/classic/global/menu/shared-menu-check@2x.png                  (../../shared/menu-check@2x.png)
+* skin/classic/global/in-content/common.css                          (in-content/common.css)
+  skin/classic/global/in-content/check.png                           (../../shared/in-content/check.png)
+  skin/classic/global/in-content/check@2x.png                        (../../shared/in-content/check@2x.png)
+  skin/classic/global/in-content/dropdown.png                        (../../shared/in-content/dropdown.png)
+  skin/classic/global/in-content/dropdown@2x.png                     (../../shared/in-content/dropdown@2x.png)
+  skin/classic/global/in-content/dropdown-disabled.png               (../../shared/in-content/dropdown-disabled.png)
+  skin/classic/global/in-content/dropdown-disabled@2x.png            (../../shared/in-content/dropdown-disabled@2x.png)
+  skin/classic/global/in-content/help-glyph.png                      (../../shared/in-content/help-glyph.png)
+  skin/classic/global/in-content/help-glyph@2x.png                   (../../shared/in-content/help-glyph@2x.png)
+  skin/classic/global/in-content/sorter.png                          (../../shared/in-content/sorter.png)
+  skin/classic/global/in-content/sorter@2x.png                       (../../shared/in-content/sorter@2x.png)
   skin/classic/global/scale/scale-tray-horiz.gif                     (scale/scale-tray-horiz.gif)
   skin/classic/global/scale/scale-tray-vert.gif                      (scale/scale-tray-vert.gif)
   skin/classic/global/splitter/dimple.png                            (splitter/dimple.png)
   skin/classic/global/splitter/grip-bottom.gif                       (splitter/grip-bottom.gif)
   skin/classic/global/splitter/grip-top.gif                          (splitter/grip-top.gif)
   skin/classic/global/splitter/grip-left.gif                         (splitter/grip-left.gif)
   skin/classic/global/splitter/grip-right.gif                        (splitter/grip-right.gif)
   skin/classic/global/toolbar/spring.png                             (toolbar/spring.png)
--- a/toolkit/themes/osx/mozapps/extensions/extensions.css
+++ b/toolkit/themes/osx/mozapps/extensions/extensions.css
@@ -1103,16 +1103,20 @@ setting[type="radio"] > radiogroup {
 
 
 /*** buttons ***/
 
 .addon-control[disabled="true"] {
   display: none;
 }
 
+.addon-control.no-auto-hide {
+  display: block;
+}
+
 button.button-link {
   -moz-appearance: none;
   background: transparent;
   border: none;
   box-shadow: none;
   text-decoration: underline;
   color: #0066CC;
   cursor: pointer;
rename from browser/themes/shared/in-content/check.png
rename to toolkit/themes/shared/in-content/check.png
rename from browser/themes/shared/in-content/check@2x.png
rename to toolkit/themes/shared/in-content/check@2x.png
rename from browser/themes/shared/in-content/common.inc.css
rename to toolkit/themes/shared/in-content/common.inc.css
--- a/browser/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -189,17 +189,17 @@ xul|button[type="menu"] > xul|*.button-b
   -moz-appearance: none;
   margin: 1px 0;
   -moz-margin-start: 10px;
   padding: 0;
   width: 10px;
   height: 16px;
   border: none;
   background-color: transparent;
-  list-style-image: url("chrome://browser/skin/in-content/dropdown.png");
+  list-style-image: url("chrome://global/skin/in-content/dropdown.png");
 }
 
 xul|*.help-button {
   min-width: 30px;
   border-radius: 2px;
   border: 1px solid #c1c1c1;
   background-color: #ffcb00;
   background-image: none;
@@ -222,24 +222,24 @@ xul|*.help-button > xul|*.button-box {
   padding-bottom: 0;
   padding-right: 0 !important;
   padding-left: 0 !important;
 }
 
 xul|*.help-button > xul|*.button-box > xul|*.button-icon {
   width: 26px;
   height: 26px;
-  background-image: url("chrome://browser/skin/in-content/help-glyph.png");
+  background-image: url("chrome://global/skin/in-content/help-glyph.png");
   background-position: center;
 }
 
 @media (min-resolution: 2dppx) {
   xul|*.help-button > xul|*.button-box > xul|*.button-icon {
     background-size: 26px 26px;
-    background-image: url("chrome://browser/skin/in-content/help-glyph@2x.png");
+    background-image: url("chrome://global/skin/in-content/help-glyph@2x.png");
   }
 }
 
 xul|*.help-button > xul|*.button-box > xul|*.button-text {
   display: none;
 }
 
 xul|*.spinbuttons-button {
@@ -278,31 +278,31 @@ xul|*.spinbuttons-down[disabled="true"] 
 }
 
 xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker {
   -moz-appearance: none;
   -moz-margin-end: 10px;
   padding: 0;
   border: none;
   background-color: transparent;
-  list-style-image: url("chrome://browser/skin/in-content/dropdown.png");
+  list-style-image: url("chrome://global/skin/in-content/dropdown.png");
 }
 
 xul|menulist[disabled="true"]:not([editable="true"]) > xul|*.menulist-dropmarker {
-  list-style-image: url("chrome://browser/skin/in-content/dropdown-disabled.png")
+  list-style-image: url("chrome://global/skin/in-content/dropdown-disabled.png")
 }
 
 @media (min-resolution: 2dppx) {
   xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker,
   xul|button[type="menu"] > xul|*.button-box > xul|*.button-menu-dropmarker {
-    list-style-image: url("chrome://browser/skin/in-content/dropdown@2x.png");
+    list-style-image: url("chrome://global/skin/in-content/dropdown@2x.png");
   }
 
   xul|menulist[disabled="true"]:not([editable="true"]) > xul|*.menulist-dropmarker {
-    list-style-image: url("chrome://browser/skin/in-content/dropdown-disabled@2x.png")
+    list-style-image: url("chrome://global/skin/in-content/dropdown-disabled@2x.png")
   }
 
   xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker > xul|*.dropmarker-icon,
   xul|button[type="menu"] > xul|*.button-box > xul|*.button-menu-dropmarker > xul|*.dropmarker-icon {
     width: 10px;
     height: 16px;
   }
 }
@@ -426,34 +426,34 @@ xul|*.checkbox-check {
   box-shadow: 0 1px 1px 0 #fff, inset 0 2px 0 0 rgba(0,0,0,0.03);
 }
 
 xul|checkbox:not([disabled="true"]):hover > xul|*.checkbox-check {
   border-color: #0095dd;
 }
 
 xul|*.checkbox-check[checked] {
-  background-image: url("chrome://browser/skin/in-content/check.png"),
+  background-image: url("chrome://global/skin/in-content/check.png"),
                     /* !important needed to override toolkit !important rule */
                     linear-gradient(#fff, rgba(255,255,255,0.8)) !important;
 }
 
 xul|checkbox[disabled="true"] > xul|*.checkbox-check {
   opacity: 0.5;
 }
 
 xul|*.checkbox-label-box {
   -moz-margin-start: -1px; /* negative margin for the transparent border */
   -moz-padding-start: 0;
 }
 
 @media (min-resolution: 2dppx) {
   xul|*.checkbox-check[checked] {
     background-size: 12px 12px, auto;
-    background-image: url("chrome://browser/skin/in-content/check@2x.png"),
+    background-image: url("chrome://global/skin/in-content/check@2x.png"),
                       linear-gradient(#fff, rgba(255,255,255,0.8)) !important;
   }
 }
 
 xul|*.radio-check {
   -moz-appearance: none;
   width: 23px;
   height: 23px;
rename from browser/themes/shared/in-content/dropdown-disabled.png
rename to toolkit/themes/shared/in-content/dropdown-disabled.png
rename from browser/themes/shared/in-content/dropdown-disabled@2x.png
rename to toolkit/themes/shared/in-content/dropdown-disabled@2x.png
rename from browser/themes/shared/in-content/dropdown.png
rename to toolkit/themes/shared/in-content/dropdown.png
rename from browser/themes/shared/in-content/dropdown@2x.png
rename to toolkit/themes/shared/in-content/dropdown@2x.png
rename from browser/themes/shared/in-content/help-glyph.png
rename to toolkit/themes/shared/in-content/help-glyph.png
rename from browser/themes/shared/in-content/help-glyph@2x.png
rename to toolkit/themes/shared/in-content/help-glyph@2x.png
rename from browser/themes/shared/in-content/sorter.png
rename to toolkit/themes/shared/in-content/sorter.png
rename from browser/themes/shared/in-content/sorter@2x.png
rename to toolkit/themes/shared/in-content/sorter@2x.png
rename from browser/themes/windows/in-content/common.css
rename to toolkit/themes/windows/global/in-content/common.css
--- a/browser/themes/windows/in-content/common.css
+++ b/toolkit/themes/windows/global/in-content/common.css
@@ -1,13 +1,13 @@
 /* - This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-%include ../../shared/in-content/common.inc.css
+%include ../../../shared/in-content/common.inc.css
 
 xul|caption {
   background-color: transparent;
 }
 
 xul|button,
 xul|colorpicker[type="button"],
 xul|menulist {
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -164,16 +164,27 @@ toolkit.jar:
         skin/classic/global/media/throbber.png                   (media/throbber.png)
         skin/classic/global/media/stalled.png                    (media/stalled.png)
         skin/classic/global/media/volume-empty.png               (media/volume-empty.png)
         skin/classic/global/media/volume-full.png                (media/volume-full.png)
         skin/classic/global/media/error.png                      (media/error.png)
         skin/classic/global/media/clicktoplay-bgtexture.png      (media/clicktoplay-bgtexture.png)
         skin/classic/global/media/videoClickToPlayButton.svg     (media/videoClickToPlayButton.svg)
         skin/classic/global/menu/shared-menu-check.png           (../../shared/menu-check.png)
+*       skin/classic/global/in-content/common.css                (in-content/common.css)
+        skin/classic/global/in-content/check.png                 (../../shared/in-content/check.png)
+        skin/classic/global/in-content/check@2x.png              (../../shared/in-content/check@2x.png)
+        skin/classic/global/in-content/dropdown.png              (../../shared/in-content/dropdown.png)
+        skin/classic/global/in-content/dropdown@2x.png           (../../shared/in-content/dropdown@2x.png)
+        skin/classic/global/in-content/dropdown-disabled.png     (../../shared/in-content/dropdown-disabled.png)
+        skin/classic/global/in-content/dropdown-disabled@2x.png  (../../shared/in-content/dropdown-disabled@2x.png)
+        skin/classic/global/in-content/help-glyph.png            (../../shared/in-content/help-glyph.png)
+        skin/classic/global/in-content/help-glyph@2x.png         (../../shared/in-content/help-glyph@2x.png)
+        skin/classic/global/in-content/sorter.png                (../../shared/in-content/sorter.png)
+        skin/classic/global/in-content/sorter@2x.png             (../../shared/in-content/sorter@2x.png)
         skin/classic/global/printpreview/arrow-left.png          (printpreview/arrow-left.png)
         skin/classic/global/printpreview/arrow-left-end.png      (printpreview/arrow-left-end.png)
         skin/classic/global/printpreview/arrow-right.png         (printpreview/arrow-right.png)
         skin/classic/global/printpreview/arrow-right-end.png     (printpreview/arrow-right-end.png)
         skin/classic/global/radio/radio-check.gif                (radio/radio-check.gif)
         skin/classic/global/radio/radio-check-dis.gif            (radio/radio-check-dis.gif)
         skin/classic/global/scrollbar/slider.gif                 (scrollbar/slider.gif)
         skin/classic/global/splitter/grip-bottom.gif             (splitter/grip-bottom.gif)
@@ -347,16 +358,27 @@ toolkit.jar:
         skin/classic/aero/global/media/throbber.png                      (media/throbber.png)
         skin/classic/aero/global/media/stalled.png                       (media/stalled.png)
         skin/classic/aero/global/media/volume-empty.png                  (media/volume-empty.png)
         skin/classic/aero/global/media/volume-full.png                   (media/volume-full.png)
         skin/classic/aero/global/media/error.png                         (media/error.png)
         skin/classic/aero/global/media/clicktoplay-bgtexture.png         (media/clicktoplay-bgtexture.png)
         skin/classic/aero/global/media/videoClickToPlayButton.svg        (media/videoClickToPlayButton.svg)
         skin/classic/aero/global/menu/shared-menu-check.png              (../../shared/menu-check.png)
+*       skin/classic/aero/global/in-content/common.css                   (in-content/common.css)
+        skin/classic/aero/global/in-content/check.png                    (../../shared/in-content/check.png)
+        skin/classic/aero/global/in-content/check@2x.png                 (../../shared/in-content/check@2x.png)
+        skin/classic/aero/global/in-content/dropdown.png                 (../../shared/in-content/dropdown.png)
+        skin/classic/aero/global/in-content/dropdown@2x.png              (../../shared/in-content/dropdown@2x.png)
+        skin/classic/aero/global/in-content/dropdown-disabled.png        (../../shared/in-content/dropdown-disabled.png)
+        skin/classic/aero/global/in-content/dropdown-disabled@2x.png     (../../shared/in-content/dropdown-disabled@2x.png)
+        skin/classic/aero/global/in-content/help-glyph.png               (../../shared/in-content/help-glyph.png)
+        skin/classic/aero/global/in-content/help-glyph@2x.png            (../../shared/in-content/help-glyph@2x.png)
+        skin/classic/aero/global/in-content/sorter.png                   (../../shared/in-content/sorter.png)
+        skin/classic/aero/global/in-content/sorter@2x.png                (../../shared/in-content/sorter@2x.png)
         skin/classic/aero/global/printpreview/arrow-left.png             (printpreview/arrow-left-aero.png)
         skin/classic/aero/global/printpreview/arrow-left-end.png         (printpreview/arrow-left-end-aero.png)
         skin/classic/aero/global/printpreview/arrow-right.png            (printpreview/arrow-right-aero.png)
         skin/classic/aero/global/printpreview/arrow-right-end.png        (printpreview/arrow-right-end-aero.png)
         skin/classic/aero/global/radio/radio-check.gif                   (radio/radio-check.gif)
         skin/classic/aero/global/radio/radio-check-dis.gif               (radio/radio-check-dis.gif)
         skin/classic/aero/global/scrollbar/slider.gif                    (scrollbar/slider.gif)
         skin/classic/aero/global/splitter/grip-bottom.gif                (splitter/grip-bottom.gif)
--- a/toolkit/themes/windows/mozapps/extensions/extensions.css
+++ b/toolkit/themes/windows/mozapps/extensions/extensions.css
@@ -1119,16 +1119,20 @@ menulist { /* Fixes some styling inconsi
 
 
 /*** buttons ***/
 
 .addon-control[disabled="true"] {
   display: none;
 }
 
+.addon-control.no-auto-hide {
+  display: block;
+}
+
 button.button-link {
   -moz-appearance: none;
   background: transparent;
   border: none;
   box-shadow: none;
   text-decoration: underline;
   color: #0066CC;
   cursor: pointer;