Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 18 Apr 2016 15:14:45 -0700
changeset 331546 08763e0e411fce69e74a49422af5ba9345bb1ad8
parent 331545 67cd0f4372e924d0d9e7bc8c56fc41015191b09e (current diff)
parent 331506 67ac40fb8f680ea5e03805552187ba1b5e8392a1 (diff)
child 331547 cb9908e330d178d06ba9af56dc7c9c963688489b
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.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 MozReview-Commit-ID: KlkboTscjR5
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -24,18 +24,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "ResetProfile",
   "resource://gre/modules/ResetProfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
   "resource:///modules/CustomizableUI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
   "resource://gre/modules/UITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
   "resource:///modules/BrowserUITelemetry.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Metrics",
-  "resource://gre/modules/Metrics.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
   "resource://gre/modules/ReaderMode.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent",
   "resource:///modules/ReaderParent.jsm");
 
 // See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -28,18 +28,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment",
                                   "resource://gre/modules/TelemetryEnvironment.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryLog",
                                   "resource://gre/modules/TelemetryLog.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryUtils",
                                   "resource://gre/modules/TelemetryUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
                                   "resource://services-common/utils.js");
-XPCOMUtils.defineLazyModuleGetter(this, "Metrics",
-                                  "resource://gre/modules/Metrics.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter",
                                    "@mozilla.org/xre/app-info;1",
                                    "nsICrashReporter");
 
 const FILE_CACHE                = "experiments.json";
 const EXPERIMENTS_CHANGED_TOPIC = "experiments-changed";
 const MANIFEST_VERSION          = 1;
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -57,16 +57,20 @@ UNINSTALLER_PACKAGE_HOOK = $(RM) -r $(ST
 STUB_HOOK = $(NSINSTALL) -D '$(ABS_DIST)/$(PKG_INST_PATH)'; \
     $(RM) '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
     cp ../installer/windows/l10ngen/stub.exe '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
     chmod 0755 '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
     $(NULL)
 endif
 
 SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/list.txt)) ddg
+ifeq (,$(filter-out en-US ru be kk tr uk zh-CN zh-TW,$(AB_CD)))
+    SEARCHPLUGINS_NAMES := $(subst google,google:hidden,$(SEARCHPLUGINS_NAMES))
+    SEARCHPLUGINS_NAMES += google-nocodes
+endif
 SEARCHPLUGINS_FILENAMES = $(subst :hidden,,$(SEARCHPLUGINS_NAMES))
 SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD)
 SEARCHPLUGINS_TARGET := libs searchplugins
 SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(call EN_US_OR_L10N_FILE,searchplugins/$(plugin))),$(warning Missing searchplugin: $(plugin))))
 # Some locale-specific search plugins may have preprocessor directives, but the
 # default en-US ones do not.
 SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings
 PP_TARGETS += SEARCHPLUGINS
copy from browser/locales/en-US/searchplugins/google.xml
copy to browser/locales/en-US/searchplugins/google-nocodes.xml
--- a/browser/locales/en-US/searchplugins/google.xml
+++ b/browser/locales/en-US/searchplugins/google.xml
@@ -7,10 +7,12 @@
 <Description>Google Search</Description>
 <InputEncoding>UTF-8</InputEncoding>
 <Image width="16" height="16">data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///zD9/f2W/f392P39/fn9/f35/f391/39/ZT+/v4uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Cf39/Zn///////////////////////////////////////////39/ZX///8IAAAAAAAAAAAAAAAA/v7+Cf39/cH/////+v35/7TZp/92ul3/WKs6/1iqOv9yuFn/rNWd//j79v///////f39v////wgAAAAAAAAAAP39/Zn/////7PXp/3G3WP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP+Or1j//vDo///////9/f2VAAAAAP///zD/////+vz5/3G3V/9TqDT/WKo6/6LQkf/U6cz/1urO/6rUm/+Zo0r/8IZB//adZ////v7///////7+/i79/f2Y/////4nWzf9Lqkj/Vqo4/9Xqzv///////////////////////ebY//SHRv/0hUL//NjD///////9/f2U/f392v////8sxPH/Ebzt/43RsP/////////////////////////////////4roL/9IVC//i1jf///////f391/39/fr/////Cr37/wW8+/+16/7/////////////////9IVC//SFQv/0hUL/9IVC//SFQv/3pnX///////39/fn9/f36/////wu++/8FvPv/tuz+//////////////////SFQv/0hUL/9IVC//SFQv/0hUL/96p7///////9/f35/f392/////81yfz/CrL5/2uk9v///////////////////////////////////////////////////////f392P39/Zn/////ks/7/zdS7P84Rur/0NT6///////////////////////9/f////////////////////////39/Zb+/v4y//////n5/v9WYu3/NUPq/ztJ6/+VnPT/z9L6/9HU+v+WnfT/Ul7t/+Hj/P////////////////////8wAAAAAP39/Z3/////6Or9/1hj7v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9sdvD////////////9/f2YAAAAAAAAAAD///8K/f39w//////5+f7/paz2/11p7v88Suv/Okfq/1pm7v+iqfX/+fn+///////9/f3B/v7+CQAAAAAAAAAAAAAAAP///wr9/f2d///////////////////////////////////////////9/f2Z/v7+CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f2Z/f392/39/fr9/f36/f392v39/Zj///8wAAAAAAAAAAAAAAAAAAAAAPAPAADAAwAAgAEAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/g3+/v5X/f39mf39/cj9/f3q/f39+f39/fn9/f3q/f39yP39/Zn+/v5W////DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f2c/f399f/////////////////////////////////////////////////////9/f31/f39mv7+/iMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/gn9/f2K/f39+////////////////////////////////////////////////////////////////////////////f39+v39/Yf///8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4k/f390v////////////////////////////////////////////////////////////////////////////////////////////////39/dD///8iAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////MP39/er//////////////////////////+r05v+v16H/gsBs/2WxSf9Wqjj/Vqk3/2OwRv99vWX/pdKV/97u2P////////////////////////////39/ej+/v4vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f3q/////////////////////+v15/+Pxnv/VKk2/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/36+Z//d7tf///////////////////////39/ej///8iAAAAAAAAAAAAAAAAAAAAAAAAAAD///8K/f390//////////////////////E4bn/XKw+/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1apN/+x0pv///////////////////////39/dD///8IAAAAAAAAAAAAAAAAAAAAAP39/Yv/////////////////////sdij/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/YKU1/8qOPv/5wZ////////////////////////39/YcAAAAAAAAAAAAAAAD+/v4l/f39+////////////////8Lgt/9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9utlT/n86N/7faqv+426v/pdKV/3u8ZP9UqDX/U6g0/3egN//jiUH/9IVC//SFQv/82MP//////////////////f39+v7+/iMAAAAAAAAAAP39/Z3////////////////q9Ob/W6w+/1OoNP9TqDT/U6g0/1OoNP9nskz/zOXC/////////////////////////////////+Dv2v+osWP/8YVC//SFQv/0hUL/9IVC//WQVP/++fb//////////////////f39mgAAAAD+/v4O/f399v///////////////4LHj/9TqDT/U6g0/1OoNP9TqDT/dblc//L58P/////////////////////////////////////////////8+v/3p3f/9IVC//SFQv/0hUL/9IVC//rIqf/////////////////9/f31////DP7+/ln////////////////f9v7/Cbz2/zOwhv9TqDT/U6g0/2KwRv/v9+z///////////////////////////////////////////////////////738//1kFT/9IVC//SFQv/0hUL/9plg///////////////////////+/v5W/f39nP///////////////4jf/f8FvPv/Bbz7/yG1s/9QqDz/vN2w//////////////////////////////////////////////////////////////////rHqP/0hUL/9IVC//SFQv/0hUL//vDn//////////////////39/Zn9/f3L////////////////R878/wW8+/8FvPv/Bbz7/y7C5P/7/fr//////////////////////////////////////////////////////////////////ere//SFQv/0hUL/9IVC//SFQv/718H//////////////////f39yP39/ez///////////////8cwvv/Bbz7/wW8+/8FvPv/WNL8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//rIqv/////////////////9/f3q/f39+v///////////////we9+/8FvPv/Bbz7/wW8+/993P3///////////////////////////////////////SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/+cGf//////////////////39/fn9/f36////////////////B737/wW8+/8FvPv/Bbz7/33c/f//////////////////////////////////////9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/6xaX//////////////////f39+f39/e3///////////////8cwvv/Bbz7/wW8+/8FvPv/WdP8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//vVv//////////////////9/f3q/f39y////////////////0bN/P8FvPv/Bbz7/wW8+/8hrvn/+/v///////////////////////////////////////////////////////////////////////////////////////////////////////////////////39/cj9/f2c////////////////ht/9/wW8+/8FvPv/FZP1/zRJ6/+zuPf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////f39mf7+/lr////////////////d9v7/B7n7/yB38f81Q+r/NUPq/0hV7P/u8P3////////////////////////////////////////////////////////////////////////////////////////////////////////////+/v5X////D/39/ff///////////////9tkPT/NUPq/zVD6v81Q+r/NUPq/2Fs7//y8v7////////////////////////////////////////////09f7//////////////////////////////////////////////////f399f7+/g0AAAAA/f39n////////////////+Tm/P89Suv/NUPq/zVD6v81Q+r/NUPq/1Bc7f/IzPn/////////////////////////////////x8v5/0xY7P+MlPP////////////////////////////////////////////9/f2cAAAAAAAAAAD+/v4n/f39/P///////////////7W69/81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9ZZe7/k5v0/6609/+vtff/lJv0/1pm7v81Q+r/NUPq/zVD6v+GjvL//v7//////////////////////////////f39+/7+/iQAAAAAAAAAAAAAAAD9/f2N/////////////////////6Cn9f81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v+BivL////////////////////////////9/f2KAAAAAAAAAAAAAAAAAAAAAP7+/gv9/f3V/////////////////////7W69/8+S+v/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/P0zr/7q/+P///////////////////////f390v7+/gkAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3r/////////////////////+Xn/P94gfH/NkTq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NkTq/3Z/8f/l5/z///////////////////////39/er+/v4kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f3r///////////////////////////k5vz/nqX1/2p08P9IVez/OEbq/zdF6v9GU+z/aHLv/5qh9f/i5Pz////////////////////////////9/f3q////MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3V/////////////////////////////////////////////////////////////////////////////////////////////////f390v7+/iQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wr9/f2N/f39/P///////////////////////////////////////////////////////////////////////////f39+/39/Yv+/v4JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4n/f39n/39/ff//////////////////////////////////////////////////////f399v39/Z3+/v4lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Dv7+/lr9/f2c/f39y/39/e39/f36/f39+v39/ez9/f3L/f39nP7+/ln+/v4OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AA///AAD//AAAP/gAAB/wAAAP4AAAB8AAAAPAAAADgAAAAYAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABgAAAAcAAAAPAAAAD4AAAB/AAAA/4AAAf/AAAP/8AAP//wAP/</Image>
 <Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&amp;q={searchTerms}"/>
 <Url type="text/html" method="GET" template="https://www.google.com/search" rel="searchform">
   <Param name="q" value="{searchTerms}"/>
   <Param name="ie" value="utf-8"/>
   <Param name="oe" value="utf-8"/>
+  <Param name="client" value="firefox-b"/>
+  <MozParam name="client" condition="purpose" purpose="keyword" value="firefox-b-ab"/>
 </Url>
 </SearchPlugin>
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1954,17 +1954,22 @@ notification.pluginVulnerable > .notific
 }
 
 #UITourTooltipClose {
   -moz-margin-end: -4px;
   height: 16px;
   width: 16px;
 }
 
+/**
+ * Override the --panel-arrowcontent-padding so the background extends
+ * to the sides and bottom of the panel.
+ */
 #UITourTooltipButtons {
+  margin-left: -10px;
   margin-bottom: -10px;
 }
 
 %include ../shared/contextmenu.inc.css
 
 #context-navigation > .menuitem-iconic > .menu-iconic-left {
   visibility: visible;
   /* override toolkit/themes/linux/global/menu.css */
--- a/browser/themes/shared/UITour.inc.css
+++ b/browser/themes/shared/UITour.inc.css
@@ -22,72 +22,70 @@
      on Linux without an X compositor where opacity is either 0 or 1. */
   box-shadow: 0 0 3px 0 rgba(0,0,0,0.49);
   min-height: 32px;
   min-width: 32px;
 }
 
 #UITourTooltipBody {
   -moz-margin-end: 14px;
-}
-
-#UITourTooltipBody > vbox {
-  padding-top: 4px;
-}
-
-#UITourTooltipIconContainer {
-  -moz-margin-start: -16px;
+  -moz-margin-start: 14px;
+  margin-top: -16px;
+  margin-bottom: 8px;
 }
 
 #UITourTooltipIcon {
   width: 48px;
   height: 48px;
-  -moz-margin-start: 28px;
-  -moz-margin-end: 28px;
+  -moz-margin-start: 14px;
+  -moz-margin-end: 14px;
 }
 
 #UITourTooltipTitle,
 #UITourTooltipDescription {
   max-width: 20rem;
 }
 
 #UITourTooltipTitle {
   font-size: 1.45rem;
   font-weight: bold;
   -moz-margin-start: 0;
-  -moz-margin-end: 0;
-  margin: 0 0 9px 0;
+  /* Avoid the title overlapping the close button */
+  -moz-margin-end: 14px;
+  margin-top: 0;
+  margin-bottom: 9px;
 }
 
 #UITourTooltipDescription {
   -moz-margin-start: 0;
   -moz-margin-end: 0;
   font-size: 1.15rem;
   line-height: 1.8rem;
   margin-bottom: 0; /* Override global.css */
 }
 
 #UITourTooltipClose {
+  position: relative;
   -moz-appearance: none;
   border: none;
   background-color: transparent;
   min-width: 0;
   -moz-margin-start: 4px;
   margin-top: -2px;
 }
 
 #UITourTooltipClose > .toolbarbutton-text {
   display: none;
 }
 
 #UITourTooltipButtons {
   -moz-box-pack: end;
   background-color: hsla(210,4%,10%,.07);
   border-top: 1px solid hsla(210,4%,10%,.14);
-  margin: 24px -16px -16px;
+  margin: 10px -16px -16px;
   padding: 2em 15px;
 }
 
 #UITourTooltipButtons > label,
 #UITourTooltipButtons > button {
   margin: 0 15px;
 }
 
--- a/devtools/client/framework/test/shared-head.js
+++ b/devtools/client/framework/test/shared-head.js
@@ -260,26 +260,40 @@ var openToolboxForTab = Task.async(funct
  * toolbox has been opened. Resolves to the toolbox.
  */
 var openNewTabAndToolbox = Task.async(function*(url, toolId, hostType) {
   let tab = yield addTab(url);
   return openToolboxForTab(tab, toolId, hostType)
 });
 
 /**
+ * Close a tab and if necessary, the toolbox that belongs to it
+ * @param {Tab} tab The tab to close.
+ * @return {Promise} Resolves when the toolbox and tab have been destroyed and
+ * closed.
+ */
+var closeTabAndToolbox = Task.async(function*(tab = gBrowser.selectedTab) {
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  if (target) {
+    yield gDevTools.closeToolbox(target);
+  }
+
+  yield removeTab(gBrowser.selectedTab);
+});
+
+/**
  * Close a toolbox and the current tab.
  * @param {Toolbox} toolbox The toolbox to close.
  * @return {Promise} Resolves when the toolbox and tab have been destroyed and
  * closed.
  */
-function closeToolboxAndTab(toolbox) {
-  return toolbox.destroy().then(function() {
-    gBrowser.removeCurrentTab();
-  });
-}
+var closeToolboxAndTab = Task.async(function*(toolbox) {
+  yield toolbox.destroy();
+  yield removeTab(gBrowser.selectedTab);
+});
 
 /**
  * Waits until a predicate returns true.
  *
  * @param function predicate
  *        Invoked once in a while until it returns true.
  * @param number interval [optional]
  *        How often the predicate is invoked, in milliseconds.
--- a/devtools/client/inspector/rules/test/browser_rules_edit-selector-click.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector-click.js
@@ -31,25 +31,25 @@ function* testClickOnSelectorEditorInput
   info("Focusing an existing selector name in the rule-view");
   let editor = yield focusEditableField(view, ruleEditor.selectorText);
   let editorInput = editor.input;
   is(inplaceEditor(ruleEditor.selectorText), editor,
     "The selector editor got focused");
 
   info("Click inside the editor input");
   let onClick = once(editorInput, "click");
-  EventUtils.synthesizeMouse(editor.input, 1, 1, {}, view.styleWindow);
+  EventUtils.synthesizeMouse(editor.input, 2, 1, {}, view.styleWindow);
   yield onClick;
   is(editor.input, view.styleDocument.activeElement,
     "The editor input should still be focused");
   ok(!ruleEditor.newPropSpan, "No newProperty editor was created");
 
   info("Doubleclick inside the editor input");
   let onDoubleClick = once(editorInput, "dblclick");
-  EventUtils.synthesizeMouse(editor.input, 1, 1, { clickCount: 2 },
+  EventUtils.synthesizeMouse(editor.input, 2, 1, { clickCount: 2 },
     view.styleWindow);
   yield onDoubleClick;
   is(editor.input, view.styleDocument.activeElement,
     "The editor input should still be focused");
   ok(!ruleEditor.newPropSpan, "No newProperty editor was created");
 
   info("Click outside the editor input");
   let onBlur = once(editorInput, "blur");
--- a/devtools/client/shared/components/h-split-box.js
+++ b/devtools/client/shared/components/h-split-box.js
@@ -125,17 +125,17 @@ module.exports = createClass({
         {
           className: "h-split-box-pane",
           style: { flex: startWidth, minWidth: minStartWidth },
         },
         start
       ),
 
       dom.div({
-        className: "h-split-box-splitter",
+        className: "devtools-side-splitter",
         onMouseDown: this._onMouseDown,
       }),
 
       dom.div(
         {
           className: "h-split-box-pane",
           style: { flex: 1 - startWidth, minWidth: minEndWidth },
         },
--- a/devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html
+++ b/devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html
@@ -4,16 +4,17 @@
 Basic tests for the HSplitBox component.
 -->
 <head>
   <meta charset="utf-8">
   <title>Tree component test</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript "src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <link rel="stylesheet" href="chrome://devtools/skin/splitters.css" type="text/css"/>
   <link rel="stylesheet" href="chrome://devtools/skin/components-h-split-box.css" type="text/css"/>
   <style>
     html {
       --theme-splitter-color: black;
     }
   </style>
 </head>
 <body>
@@ -72,17 +73,17 @@ window.onload = Task.async(function* () 
     const threeQuarters = left + 3 * width / 4;
 
     synthesizeMouse(container, middle, top, { type: "mousemove" }, window);
     is(newSizes.length, 0, "Mouse moves without dragging the splitter should have no effect");
 
     // Send a mouse down on the splitter, and then move the mouse a couple
     // times. Now we should get resizes.
 
-    const splitter = document.querySelector(".h-split-box-splitter");
+    const splitter = document.querySelector(".devtools-side-splitter");
     ok(splitter, "Should get our splitter");
 
     synthesizeMouseAtCenter(splitter, { button: 0, type: "mousedown" }, window);
 
     function mouseMove(clientX) {
       const event = new MouseEvent("mousemove", { clientX });
       document.defaultView.top.dispatchEvent(event);
     }
--- a/devtools/client/shared/widgets/TableWidget.js
+++ b/devtools/client/shared/widgets/TableWidget.js
@@ -1675,17 +1675,17 @@ EditableFieldsEngine.prototype = {
    * @param  {Node} target
    *         Dom node to be edited.
    */
   edit: function(target) {
     if (!target) {
       return;
     }
 
-    target.scrollIntoView();
+    target.scrollIntoView(false);
     target.focus();
 
     if (!target.matches(this.selectors.join(","))) {
       return;
     }
 
     // If we are actively editing something complete the edit first.
     if (this.isEditing) {
--- a/devtools/client/storage/test/head.js
+++ b/devtools/client/storage/test/head.js
@@ -838,17 +838,17 @@ function waitForContextMenu(popup, butto
     deferred.resolve(popup);
   }
 
   popup.addEventListener("popupshown", onPopupShown);
 
   info("wait for the context menu to open");
   button.scrollIntoView();
   let eventDetails = {type: "contextmenu", button: 2};
-  EventUtils.synthesizeMouse(button, 2, 2, eventDetails,
+  EventUtils.synthesizeMouse(button, 5, 2, eventDetails,
                              button.ownerDocument.defaultView);
   return deferred.promise;
 }
 
 /**
  * Verify the storage inspector state: check that given type/host exists
  * in the tree, and that the table contains rows with specified names.
  *
--- a/devtools/client/themes/components-h-split-box.css
+++ b/devtools/client/themes/components-h-split-box.css
@@ -17,15 +17,8 @@
   height: 100%;
 }
 
 .h-split-box {
   display: flex;
   flex-direction: row;
   flex: 1;
 }
-
-.h-split-box-splitter {
-  -moz-border-end: 1px solid var(--theme-splitter-color);
-  cursor: ew-resize;
-  width: 3px;
-  -moz-margin-start: -3px;
-}
--- a/devtools/client/themes/splitters.css
+++ b/devtools/client/themes/splitters.css
@@ -1,43 +1,79 @@
 /* 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/. */
 
+/* This file is loaded by both browser.xul and toolbox.xul. Therefore, rules
+   defined here can not rely on toolbox.xul variables. */
+
 /* Splitters */
+
+:root {
+  /* Define the widths of the draggable areas on each side of a splitter. top
+     and bottom widths are used for horizontal splitters, inline-start and
+     inline-end for side splitters.*/
+
+  --devtools-splitter-top-width: 2px;
+  --devtools-splitter-bottom-width: 2px;
+
+  /* Small draggable area on inline-start to avoid overlaps on scrollbars.*/
+  --devtools-splitter-inline-start-width: 1px;
+  --devtools-splitter-inline-end-width: 4px;
+}
+
 :root[devtoolstheme="light"] {
   /* These variables are used in browser.xul but inside the toolbox they are overridden by --theme-splitter-color */
   --devtools-splitter-color: #dde1e4;
 }
 
 :root[devtoolstheme="dark"] {
   --devtools-splitter-color: #42484f;
 }
 
-.devtools-horizontal-splitter {
+.devtools-horizontal-splitter,
+.devtools-side-splitter {
   -moz-appearance: none;
   background-image: none;
-  background-color: transparent;
   border: 0;
-  border-bottom: 1px solid var(--devtools-splitter-color);
-  min-height: 3px;
-  height: 3px;
-  margin-top: -3px;
+  border-style: solid;
+  border-color: transparent;
+  background-color: var(--devtools-splitter-color);
+  background-clip: content-box;
   position: relative;
+
+  box-sizing: border-box;
+
+  /* Positive z-index positions the splitter on top of its siblings and makes
+     it clickable on both sides. */
+  z-index: 1;
+}
+
+.devtools-horizontal-splitter {
+  min-height: calc(var(--devtools-splitter-top-width) +
+    var(--devtools-splitter-bottom-width) + 1px);
+
+  border-top-width: var(--devtools-splitter-top-width);
+  border-bottom-width: var(--devtools-splitter-bottom-width);
+
+  margin-top: calc(-1 * var(--devtools-splitter-top-width) - 1px);
+  margin-bottom: calc(-1 * var(--devtools-splitter-bottom-width));
+
+  cursor: n-resize;
 }
 
 .devtools-side-splitter {
-  -moz-appearance: none;
-  background-image: none;
-  background-color: transparent;
-  border: 0;
-  -moz-border-end: 1px solid var(--devtools-splitter-color);
-  min-width: 3px;
-  width: 3px;
-  -moz-margin-start: -3px;
-  position: relative;
+  min-width: calc(var(--devtools-splitter-inline-start-width) +
+    var(--devtools-splitter-inline-end-width) + 1px);
+
+  border-inline-start-width: var(--devtools-splitter-inline-start-width);
+  border-inline-end-width: var(--devtools-splitter-inline-end-width);
+
+  margin-inline-start: calc(-1 * var(--devtools-splitter-inline-start-width) - 1px);
+  margin-inline-end: calc(-1 * var(--devtools-splitter-inline-end-width));
+
   cursor: e-resize;
 }
 
 .devtools-horizontal-splitter.disabled,
 .devtools-side-splitter.disabled {
   pointer-events: none;
 }
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -975,26 +975,24 @@
 
 .hidden-labels-box:not(.visible) > label,
 .hidden-labels-box.visible ~ .hidden-labels-box > label:last-child {
   display: none;
 }
 
 .devtools-invisible-splitter {
   border-color: transparent;
+  background-color: transparent;
 }
 
-.devtools-horizontal-splitter {
-  border-bottom: 1px solid var(--theme-splitter-color);
+.devtools-horizontal-splitter,
+.devtools-side-splitter {
+  background-color: var(--theme-splitter-color);
 }
 
-.devtools-side-splitter {
-  -moz-border-end: 1px solid var(--theme-splitter-color);
-  border-color: var(--theme-splitter-color); /* Needed for responsive container at low width. */
-}
 
 /* Throbbers */
 .devtools-throbber::before {
   content: "";
   display: inline-block;
   vertical-align: bottom;
   -moz-margin-end: 0.5em;
   width: 1em;
--- a/devtools/client/themes/widgets.css
+++ b/devtools/client/themes/widgets.css
@@ -59,27 +59,29 @@
 @media (max-width: 700px) {
   .devtools-responsive-container {
     -moz-box-orient: vertical;
   }
 
   .devtools-responsive-container > .devtools-side-splitter {
     /* This is a normally vertical splitter, but we have turned it horizontal
        due to the smaller resolution */
-    min-height: 3px;
-    height: 3px;
-    margin-top: -3px;
+    min-height: calc(var(--devtools-splitter-top-width) +
+    var(--devtools-splitter-bottom-width) + 1px);
+    border-top-width: var(--devtools-splitter-top-width);
+    border-bottom-width: var(--devtools-splitter-bottom-width);
+    margin-top: calc(-1 * var(--devtools-splitter-top-width) - 1px);
+    margin-bottom: calc(-1 * var(--devtools-splitter-bottom-width));
 
     /* Reset the vertical splitter styles */
-    border-width: 0;
-    border-bottom-width: 1px;
-    border-bottom-style: solid;
-    -moz-margin-start: 0;
-    width: auto;
     min-width: 0;
+    border-inline-end-width: 0;
+    border-inline-start-width: 0;
+    margin-inline-end: 0;
+    margin-inline-start: 0;
 
     /* In some edge case the cursor is not changed to n-resize */
     cursor: n-resize;
   }
 
   .devtools-responsive-container > .devtools-sidebar-tabs:not([pane-collapsed]) {
     /* When the panel is collapsed min/max height should not be applied because
        collapsing relies on negative margins, which implies constant height. */
@@ -1118,17 +1120,17 @@
   color: var(--theme-body-color);
 }
 
 /* Table Widget */
 
 /* Table body */
 
 .table-widget-body > .devtools-side-splitter {
-  border: none;
+  background-color: transparent;
 }
 
 .table-widget-body {
   overflow: auto;
 }
 
 .table-widget-body,
 .table-widget-empty-text {
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging.js
@@ -16,16 +16,24 @@ const TEST_DATA_JSON_CONTENT =
 
 const PAGE_REQUEST_PREDICATE =
   ({ request }) => request.url.endsWith("test-network-request.html");
 
 const TEST_DATA_REQUEST_PREDICATE =
   ({ request }) => request.url.endsWith("test-data.json");
 
 add_task(function* testPageLoad() {
+  // Enable logging in the UI.  Not needed to pass test but makes it easier
+  // to debug interactively.
+  yield new Promise(resolve => {
+    SpecialPowers.pushPrefEnv({"set":
+      [["devtools.webconsole.filter.networkinfo", true]
+    ]}, resolve);
+  });
+
   let finishedRequest = waitForFinishedRequest(PAGE_REQUEST_PREDICATE);
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
   let request = yield finishedRequest;
 
   ok(request, "Page load was logged");
 
   let client = hud.ui.webConsoleClient;
   let args = [request.actor];
@@ -35,16 +43,18 @@ add_task(function* testPageLoad() {
   is(request.request.url, TEST_NETWORK_REQUEST_URI,
     "Logged network entry is page load");
   is(request.request.method, "GET", "Method is correct");
   ok(!postData.postData.text, "No request body was stored");
   ok(!postData.postDataDiscarded,
     "Request body was not discarded");
   is(responseContent.content.text.indexOf("<!DOCTYPE HTML>"), 0,
     "Response body's beginning is okay");
+
+  yield closeTabAndToolbox();
 });
 
 add_task(function* testXhrGet() {
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
 
   let finishedRequest = waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
   content.wrappedJSObject.testXhrGet();
   let request = yield finishedRequest;
@@ -57,16 +67,18 @@ add_task(function* testXhrGet() {
   const responseContent = yield getPacket(client, "getResponseContent", args);
 
   is(request.request.method, "GET", "Method is correct");
   ok(!postData.postData.text, "No request body was sent");
   ok(!postData.postDataDiscarded,
     "Request body was not discarded");
   is(responseContent.content.text, TEST_DATA_JSON_CONTENT,
     "Response is correct");
+
+  yield closeTabAndToolbox();
 });
 
 add_task(function* testXhrPost() {
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
 
   let finishedRequest = waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
   content.wrappedJSObject.testXhrPost();
   let request = yield finishedRequest;
@@ -77,16 +89,18 @@ add_task(function* testXhrPost() {
   let args = [request.actor];
   const postData = yield getPacket(client, "getRequestPostData", args);
   const responseContent = yield getPacket(client, "getResponseContent", args);
 
   is(request.request.method, "POST", "Method is correct");
   is(postData.postData.text, "Hello world!", "Request body was logged");
   is(responseContent.content.text, TEST_DATA_JSON_CONTENT,
     "Response is correct");
+
+  yield closeTabAndToolbox();
 });
 
 add_task(function* testFormSubmission() {
   let pageLoadRequestFinished = waitForFinishedRequest(PAGE_REQUEST_PREDICATE);
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
 
   info("Waiting for the page load to be finished.")
   yield pageLoadRequestFinished;
@@ -112,9 +126,11 @@ add_task(function* testFormSubmission() 
     .indexOf("Content-Type: application/x-www-form-urlencoded"), -1,
     "Content-Type is correct");
   isnot(postData.postData.text
     .indexOf("Content-Length: 20"), -1, "Content-length is correct");
   isnot(postData.postData.text
     .indexOf("name=foo+bar&age=144"), -1, "Form data is correct");
   is(responseContent.content.text.indexOf("<!DOCTYPE HTML>"), 0,
     "Response body's beginning is okay");
+
+  yield closeTabAndToolbox();
 });
--- a/devtools/client/webconsole/test/head.js
+++ b/devtools/client/webconsole/test/head.js
@@ -278,17 +278,17 @@ function waitForContextMenu(popup, butto
 
     deferred.resolve(popup);
   }
 
   popup.addEventListener("popupshown", onPopupShown);
 
   info("wait for the context menu to open");
   let eventDetails = {type: "contextmenu", button: 2};
-  EventUtils.synthesizeMouse(button, 2, 2, eventDetails,
+  EventUtils.synthesizeMouse(button, 5, 2, eventDetails,
                              button.ownerDocument.defaultView);
   return deferred.promise;
 }
 
 /**
  * Listen for a new tab to open and return a promise that resolves when one
  * does and completes the load event.
  * @return a promise that resolves to the tab object
--- a/mobile/android/base/AppConstants.java.in
+++ b/mobile/android/base/AppConstants.java.in
@@ -63,17 +63,16 @@ public class AppConstants {
          * If our MAX_SDK_VERSION is lower than ICS, we must not be an ICS device.
          * Otherwise, we need a range check.
          */
         public static final boolean preMarshmallow = MAX_SDK_VERSION < 23 || (MIN_SDK_VERSION < 23 && Build.VERSION.SDK_INT < 23);
         public static final boolean preLollipop = MAX_SDK_VERSION < 21 || (MIN_SDK_VERSION < 21 && Build.VERSION.SDK_INT < 21);
         public static final boolean preJBMR2 = MAX_SDK_VERSION < 18 || (MIN_SDK_VERSION < 18 && Build.VERSION.SDK_INT < 18);
         public static final boolean preJBMR1 = MAX_SDK_VERSION < 17 || (MIN_SDK_VERSION < 17 && Build.VERSION.SDK_INT < 17);
         public static final boolean preJB = MAX_SDK_VERSION < 16 || (MIN_SDK_VERSION < 16 && Build.VERSION.SDK_INT < 16);
-        public static final boolean preICS = MAX_SDK_VERSION < 14 || (MIN_SDK_VERSION < 14 && Build.VERSION.SDK_INT < 14);
     }
 
     /**
      * The name of the Java class that represents the android application.
      */
     public static final String MOZ_ANDROID_APPLICATION_CLASS = "@MOZ_ANDROID_APPLICATION_CLASS@";
     /**
      * The name of the Java class that launches the browser activity.
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -3207,18 +3207,17 @@ public class BrowserApp extends GeckoApp
         final MenuItem desktopMode = aMenu.findItem(R.id.desktop_mode);
         final MenuItem enterGuestMode = aMenu.findItem(R.id.new_guest_session);
         final MenuItem exitGuestMode = aMenu.findItem(R.id.exit_guest_session);
 
         // Only show the "Quit" menu item on pre-ICS, television devices,
         // or if the user has explicitly enabled the clear on shutdown pref.
         // (We check the pref last to save the pref read.)
         // In ICS+, it's easy to kill an app through the task switcher.
-        final boolean visible = Versions.preICS ||
-                                HardwareUtils.isTelevision() ||
+        final boolean visible = HardwareUtils.isTelevision() ||
                                 !PrefUtils.getStringSet(GeckoSharedPrefs.forProfile(this),
                                                         ClearOnShutdownPref.PREF,
                                                         new HashSet<String>()).isEmpty();
         aMenu.findItem(R.id.quit).setVisible(visible);
 
         // If tab data is unavailable we disable most of the context menu and related items and
         // return early.
         if (tab == null || tab.getURL() == null) {
--- a/mobile/android/base/java/org/mozilla/gecko/DoorHangerPopup.java
+++ b/mobile/android/base/java/org/mozilla/gecko/DoorHangerPopup.java
@@ -323,21 +323,16 @@ public class DoorHangerPopup extends Anc
         // Make the popup focusable for accessibility. This gets done here
         // so the node can be accessibility focused, but on pre-ICS devices this
         // causes crashes, so it is done after the popup is shown.
         if (Versions.feature14Plus) {
             setFocusable(true);
         }
 
         show();
-
-        if (Versions.preICS) {
-            // Make the popup focusable for keyboard accessibility.
-            setFocusable(true);
-        }
     }
 
     //Show all inter-DoorHanger dividers (ie. Dividers on all visible DoorHangers except the last one)
     private void showDividers() {
         int count = mContent.getChildCount();
         DoorHanger lastVisibleDoorHanger = null;
 
         for (int i = 0; i < count; i++) {
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -1404,24 +1404,16 @@ public abstract class GeckoApp
         // cause a loop! See Bug 1011008, Comment 12.
         super.onConfigurationChanged(getResources().getConfiguration());
     }
 
     protected void initializeChrome() {
         mDoorHangerPopup = new DoorHangerPopup(this);
         mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
         mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
-
-        if (mCameraView == null) {
-            // Pre-ICS devices need the camera surface in a visible layout.
-            if (Versions.preICS) {
-                mCameraView = new SurfaceView(this);
-                ((SurfaceView)mCameraView).getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
-            }
-        }
     }
 
     /**
      * Loads the initial tab at Fennec startup. If we don't restore tabs, this
      * tab will be about:home, or the homepage if the use has set one.
      * If we restore tabs, we don't need to create a new tab.
      */
     protected void loadStartupTab(final int flags) {
@@ -2695,20 +2687,16 @@ public abstract class GeckoApp
         if (resultant == null) {
             return;
         }
 
         onLocaleChanged(resultant);
     }
 
     private void setSystemUiVisible(final boolean visible) {
-        if (Versions.preICS) {
-            return;
-        }
-
         ThreadUtils.postToUiThread(new Runnable() {
             @Override
             public void run() {
                 if (visible) {
                     mMainLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
                 } else {
                     mMainLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
                 }
--- a/mobile/android/base/java/org/mozilla/gecko/MemoryMonitor.java
+++ b/mobile/android/base/java/org/mozilla/gecko/MemoryMonitor.java
@@ -1,16 +1,15 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
-import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.home.ImageLoader;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
@@ -87,21 +86,16 @@ class MemoryMonitor extends BroadcastRec
             if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
                 GeckoThread.waitOnGecko();
             }
         }
     }
 
     public void onTrimMemory(int level) {
         Log.d(LOGTAG, "onTrimMemory() notification received with level " + level);
-        if (Versions.preICS) {
-            // This won't even get called pre-ICS.
-            return;
-        }
-
         if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
             // We seem to get this just by entering the task switcher or hitting the home button.
             // Seems bogus, because we are the foreground app, or at least not at the end of the LRU list.
             // Just ignore it, and if there is a real memory pressure event (CRITICAL, MODERATE, etc),
             // we'll respond appropriately.
             return;
         }
 
--- a/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuItem.java
+++ b/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuItem.java
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.menu;
 
-import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.widget.GeckoActionProvider;
 
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.view.ActionProvider;
 import android.view.ContextMenu;
@@ -112,20 +111,16 @@ public class GeckoMenuItem implements Me
     }
 
     @Override
     public boolean expandActionView() {
         return false;
     }
 
     public boolean hasActionProvider() {
-        if (Versions.preICS) {
-            return false;
-        }
-
         return (mActionProvider != null);
     }
 
     public int getActionEnum() {
         return mActionEnum;
     }
 
     public GeckoActionProvider getGeckoActionProvider() {
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -1460,22 +1460,17 @@ OnSharedPreferenceChangeListener
                     ((TwoStatePreference) preference).setChecked(value);
                 }
             }
         }
 
         @Override
         public void prefValue(String prefName, final boolean value) {
             final Preference pref = getField(prefName);
-            final CheckBoxPrefSetter prefSetter;
-            if (Versions.preICS) {
-                prefSetter = new CheckBoxPrefSetter();
-            } else {
-                prefSetter = new TwoStatePrefSetter();
-            }
+            final CheckBoxPrefSetter prefSetter = new TwoStatePrefSetter();
             ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
                     prefSetter.setBooleanPref(pref, value);
                 }
             });
         }
 
--- a/mobile/android/base/java/org/mozilla/gecko/util/InputOptionsUtils.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/InputOptionsUtils.java
@@ -3,23 +3,19 @@
  * 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.util;
 
 import android.content.Context;
 import android.content.Intent;
 import android.speech.RecognizerIntent;
-import org.mozilla.gecko.AppConstants.Versions;
 
 public class InputOptionsUtils {
     public static boolean supportsVoiceRecognizer(Context context, String prompt) {
-        if (Versions.preICS) {
-            return false;
-        }
         final Intent intent = createVoiceRecognizerIntent(prompt);
         return intent.resolveActivity(context.getPackageManager()) != null;
     }
 
     public static Intent createVoiceRecognizerIntent(String prompt) {
         final Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
         intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
         intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -872,19 +872,25 @@ var BrowserApp = {
     });
 
     NativeWindow.contextmenus.add(stringGetter("contextmenu.saveImage"),
       NativeWindow.contextmenus.imageSaveableContext,
       function(aTarget) {
         UITelemetry.addEvent("action.1", "contextmenu", null, "web_save_image");
         UITelemetry.addEvent("save.1", "contextmenu", null, "image");
 
-        ContentAreaUtils.saveImageURL(aTarget.currentURI.spec, null, "SaveImageTitle",
-                                      false, true, aTarget.ownerDocument.documentURIObject,
-                                      aTarget.ownerDocument);
+        RuntimePermissions.waitForPermissions(RuntimePermissions.WRITE_EXTERNAL_STORAGE).then(function(permissionGranted) {
+            if (!permissionGranted) {
+                return;
+            }
+
+            ContentAreaUtils.saveImageURL(aTarget.currentURI.spec, null, "SaveImageTitle",
+                                          false, true, aTarget.ownerDocument.documentURIObject,
+                                          aTarget.ownerDocument);
+        });
       });
 
     NativeWindow.contextmenus.add(stringGetter("contextmenu.setImageAs"),
       NativeWindow.contextmenus._disableRestricted("SET_IMAGE", NativeWindow.contextmenus.imageSaveableContext),
       function(aTarget) {
         UITelemetry.addEvent("action.1", "contextmenu", null, "web_background_image");
 
         let src = aTarget.src;
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AppMenuComponent.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AppMenuComponent.java
@@ -78,17 +78,21 @@ public class AppMenuComponent extends Ba
             return stringResource;
         }
     };
 
     public AppMenuComponent(final UITestContext testContext) {
         super(testContext);
     }
 
-    private void assertMenuIsNotOpen() {
+    public void assertMenuIsOpen() {
+        fAssertTrue("Menu is open", isMenuOpen());
+    }
+
+    public void assertMenuIsNotOpen() {
         fAssertFalse("Menu is not open", isMenuOpen());
     }
 
     public void assertMenuItemIsDisabledAndVisible(PageMenuItem pageMenuItem) {
         openAppMenu();
 
         // Non-legacy devices have hierarchical menu, check for parent menu item "page".
         final View parentMenuItemView = findAppMenuItemView(MenuItem.PAGE.getString(mSolo));
@@ -266,17 +270,26 @@ public class AppMenuComponent extends Ba
      *                      You must use findAppMenuItemView(menuItemTitle) to obtain it.
      *
      * @return true if app menu is open.
      */
     private boolean isMenuOpen(View menuItemView) {
         return (menuItemView != null) && (menuItemView.getVisibility() == View.VISIBLE);
     }
 
-    private void waitForMenuOpen() {
+    public void waitForMenuOpen() {
         WaitHelper.waitFor("menu to open", new Condition() {
             @Override
             public boolean isSatisfied() {
                 return isMenuOpen();
             }
         });
     }
+
+    public void waitForMenuClose() {
+        WaitHelper.waitFor("menu to close", new Condition() {
+            @Override
+            public boolean isSatisfied() {
+                return !isMenuOpen();
+            }
+        });
+    }
 }
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAppMenuPathways.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAppMenuPathways.java
@@ -5,31 +5,46 @@
 package org.mozilla.gecko.tests;
 
 import org.json.JSONObject;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.tests.components.AppMenuComponent;
 import org.mozilla.gecko.tests.helpers.GeckoHelper;
 import org.mozilla.gecko.tests.helpers.NavigationHelper;
 
+import com.robotium.solo.Solo;
+
 /**
  * Set of tests to test UI App menu and submenus the user interact with.
  */
 public class testAppMenuPathways extends UITest {
 
     /**
      * Robocop supports only a single test function per test class. Therefore, we
      * have a single top-level test function that dispatches to sub-tests.
      */
     public void testAppMenuPathways() {
         GeckoHelper.blockForReady();
 
+        _testHardwareMenuKeyOpenClose();
         _testSaveAsPDFPathway();
     }
 
+    public void _testHardwareMenuKeyOpenClose() {
+        mAppMenu.assertMenuIsNotOpen();
+
+        mSolo.sendKey(Solo.MENU);
+        mAppMenu.waitForMenuOpen();
+        mAppMenu.assertMenuIsOpen();
+
+        mSolo.sendKey(Solo.MENU);
+        mAppMenu.waitForMenuClose();
+        mAppMenu.assertMenuIsNotOpen();
+    }
+
     public void _testSaveAsPDFPathway() {
         // Page menu should be disabled in about:home.
         mAppMenu.assertMenuItemIsDisabledAndVisible(AppMenuComponent.PageMenuItem.SAVE_AS_PDF);
 
         // Generate a mock Content:LocationChange message with video mime-type for the current tab (tabId = 0).
         final JSONObject message = new JSONObject();
         try {
             message.put("contentType", "video/webm");
--- a/mobile/android/themes/core/aboutBase.css
+++ b/mobile/android/themes/core/aboutBase.css
@@ -23,26 +23,27 @@ input {
 }
 
 .header {
   color: #363B40;
   font-size: 1.1em;
   font-weight: bold;
   background-color: #f5f5f5;
   border-bottom: 2px solid;
-  -moz-border-bottom-colors: #ff9100 #f27900;
+  -moz-border-bottom-colors: #FF9500;
   display: flex;
   flex-direction: row;
   align-items: center;
+  height: 48px;
 }
 
 .header > div {
   flex: 1;
-  padding: 1em;
-  -moz-padding-start: 1.5em;
+  padding: 10px;
+  -moz-padding-start: 16px;
 }
 
 #header-button {
   background-repeat: no-repeat;
   background-position: center center;
   background-size: 33px 33px;
   flex: 0;
   height: 100%;
--- a/mobile/android/themes/core/aboutLogins.css
+++ b/mobile/android/themes/core/aboutLogins.css
@@ -30,26 +30,32 @@ body {
 }
 
 .realm {
   /* hostname is not localized, so keep the margin on the left side */
   margin-left: .67em;
 }
 
 .toolbar-buttons {
+  display: flex;
+  align-items: center;
+  justify-content: center;
   list-style: none;
+  margin: 0px;
+  padding: 0px;
+  height: 48px;
+  width: 48px;
 }
 
 .toolbar-buttons > li {
   background-position: center;
   background-size: 24px 24px;
   background-repeat: no-repeat;
   height: 20px;
   width: 20px;
-  margin: 0 15px;
 }
 
 #filter-input-container {
   position: fixed;
   bottom: 0;
   width: 100%;
   padding: 10px 0;
   display: flex;