Merge central to inbound a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 02 Nov 2016 17:31:08 -0700
changeset 363664 227bccbfea15ddf0b0105cdecf54c77fbeb87ad3
parent 363663 c3c0827d6c66d6cfdacaa6ae29b24f5b924ab851 (current diff)
parent 363386 ac55a6776435142feebf3c20bbabfee100686416 (diff)
child 363665 5fd7c7cad7599f10bd1cc6d4b0d2db984eb45437
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.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 central to inbound a=merge
browser/base/content/browser.js
browser/components/sessionstore/SessionStore.jsm
devtools/client/inspector/components/box-model.js
dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
dom/bluetooth/bluedroid/BluetoothA2dpManager.h
dom/bluetooth/bluedroid/BluetoothAvrcpManager.cpp
dom/bluetooth/bluedroid/BluetoothAvrcpManager.h
dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
dom/bluetooth/bluedroid/BluetoothDaemonHidInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonHidInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonSetupInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonSetupInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.h
dom/bluetooth/bluedroid/BluetoothGattManager.cpp
dom/bluetooth/bluedroid/BluetoothGattManager.h
dom/bluetooth/bluedroid/BluetoothHidManager.cpp
dom/bluetooth/bluedroid/BluetoothHidManager.h
dom/bluetooth/bluedroid/BluetoothMapBMessage.cpp
dom/bluetooth/bluedroid/BluetoothMapBMessage.h
dom/bluetooth/bluedroid/BluetoothMapFolder.cpp
dom/bluetooth/bluedroid/BluetoothMapFolder.h
dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp
dom/bluetooth/bluedroid/BluetoothMapSmsManager.h
dom/bluetooth/bluedroid/BluetoothOppManager.cpp
dom/bluetooth/bluedroid/BluetoothOppManager.h
dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
dom/bluetooth/bluedroid/BluetoothPbapManager.h
dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
dom/bluetooth/bluedroid/BluetoothSocket.cpp
dom/bluetooth/bluedroid/BluetoothSocket.h
dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.cpp
dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.h
dom/bluetooth/bluedroid/hfp-fallback/BluetoothHfpManager.cpp
dom/bluetooth/bluedroid/hfp-fallback/BluetoothHfpManager.h
dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.h
dom/bluetooth/bluez/BluetoothA2dpManager.cpp
dom/bluetooth/bluez/BluetoothA2dpManager.h
dom/bluetooth/bluez/BluetoothAvrcpManager.cpp
dom/bluetooth/bluez/BluetoothAvrcpManager.h
dom/bluetooth/bluez/BluetoothDBusService.cpp
dom/bluetooth/bluez/BluetoothDBusService.h
dom/bluetooth/bluez/BluetoothHfpManager.cpp
dom/bluetooth/bluez/BluetoothHfpManager.h
dom/bluetooth/bluez/BluetoothHidManager.cpp
dom/bluetooth/bluez/BluetoothHidManager.h
dom/bluetooth/bluez/BluetoothOppManager.cpp
dom/bluetooth/bluez/BluetoothOppManager.h
dom/bluetooth/bluez/BluetoothSocket.cpp
dom/bluetooth/bluez/BluetoothSocket.h
dom/bluetooth/bluez/BluetoothUnixSocketConnector.cpp
dom/bluetooth/bluez/BluetoothUnixSocketConnector.h
dom/bluetooth/common/BluetoothCommon.cpp
dom/bluetooth/common/BluetoothCommon.h
dom/bluetooth/common/BluetoothGattReplyRunnable.cpp
dom/bluetooth/common/BluetoothGattReplyRunnable.h
dom/bluetooth/common/BluetoothGattUUIDName.h
dom/bluetooth/common/BluetoothHashKeys.h
dom/bluetooth/common/BluetoothHfpManagerBase.h
dom/bluetooth/common/BluetoothInterface.cpp
dom/bluetooth/common/BluetoothInterface.h
dom/bluetooth/common/BluetoothProfileController.cpp
dom/bluetooth/common/BluetoothProfileController.h
dom/bluetooth/common/BluetoothProfileManagerBase.h
dom/bluetooth/common/BluetoothReplyRunnable.cpp
dom/bluetooth/common/BluetoothReplyRunnable.h
dom/bluetooth/common/BluetoothRilListener.cpp
dom/bluetooth/common/BluetoothRilListener.h
dom/bluetooth/common/BluetoothService.cpp
dom/bluetooth/common/BluetoothService.h
dom/bluetooth/common/BluetoothSocketObserver.h
dom/bluetooth/common/BluetoothUtils.cpp
dom/bluetooth/common/BluetoothUtils.h
dom/bluetooth/common/BluetoothUuidHelper.cpp
dom/bluetooth/common/BluetoothUuidHelper.h
dom/bluetooth/common/ObexBase.cpp
dom/bluetooth/common/ObexBase.h
dom/bluetooth/common/webapi/BluetoothAdapter.cpp
dom/bluetooth/common/webapi/BluetoothAdapter.h
dom/bluetooth/common/webapi/BluetoothClassOfDevice.cpp
dom/bluetooth/common/webapi/BluetoothClassOfDevice.h
dom/bluetooth/common/webapi/BluetoothDevice.cpp
dom/bluetooth/common/webapi/BluetoothDevice.h
dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp
dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h
dom/bluetooth/common/webapi/BluetoothGatt.cpp
dom/bluetooth/common/webapi/BluetoothGatt.h
dom/bluetooth/common/webapi/BluetoothGattAttributeEvent.cpp
dom/bluetooth/common/webapi/BluetoothGattAttributeEvent.h
dom/bluetooth/common/webapi/BluetoothGattCharacteristic.cpp
dom/bluetooth/common/webapi/BluetoothGattCharacteristic.h
dom/bluetooth/common/webapi/BluetoothGattDescriptor.cpp
dom/bluetooth/common/webapi/BluetoothGattDescriptor.h
dom/bluetooth/common/webapi/BluetoothGattServer.cpp
dom/bluetooth/common/webapi/BluetoothGattServer.h
dom/bluetooth/common/webapi/BluetoothGattService.cpp
dom/bluetooth/common/webapi/BluetoothGattService.h
dom/bluetooth/common/webapi/BluetoothLeDeviceEvent.cpp
dom/bluetooth/common/webapi/BluetoothLeDeviceEvent.h
dom/bluetooth/common/webapi/BluetoothManager.cpp
dom/bluetooth/common/webapi/BluetoothManager.h
dom/bluetooth/common/webapi/BluetoothMapRequestHandle.cpp
dom/bluetooth/common/webapi/BluetoothMapRequestHandle.h
dom/bluetooth/common/webapi/BluetoothObexAuthHandle.cpp
dom/bluetooth/common/webapi/BluetoothObexAuthHandle.h
dom/bluetooth/common/webapi/BluetoothPairingHandle.cpp
dom/bluetooth/common/webapi/BluetoothPairingHandle.h
dom/bluetooth/common/webapi/BluetoothPairingListener.cpp
dom/bluetooth/common/webapi/BluetoothPairingListener.h
dom/bluetooth/common/webapi/BluetoothPbapRequestHandle.cpp
dom/bluetooth/common/webapi/BluetoothPbapRequestHandle.h
dom/bluetooth/common/webapi/BluetoothUUID.cpp
dom/bluetooth/common/webapi/BluetoothUUID.h
dom/bluetooth/ipc/BluetoothChild.cpp
dom/bluetooth/ipc/BluetoothChild.h
dom/bluetooth/ipc/BluetoothMessageUtils.h
dom/bluetooth/ipc/BluetoothParent.cpp
dom/bluetooth/ipc/BluetoothParent.h
dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
dom/bluetooth/ipc/BluetoothServiceChildProcess.h
dom/bluetooth/ipc/BluetoothTypes.ipdlh
dom/bluetooth/ipc/PBluetooth.ipdl
dom/bluetooth/ipc/PBluetoothRequest.ipdl
dom/bluetooth/moz.build
dom/bluetooth/tests/marionette/head.js
dom/bluetooth/tests/marionette/manifest.ini
dom/bluetooth/tests/marionette/test_dom_BluetoothAdapter_discovery.js
dom/bluetooth/tests/marionette/test_dom_BluetoothAdapter_enable.js
dom/bluetooth/tests/marionette/test_dom_BluetoothAdapter_pair.js
dom/bluetooth/tests/marionette/test_dom_BluetoothAdapter_setters.js
dom/bluetooth/tests/marionette/test_dom_BluetoothDevice.js
dom/bluetooth/tests/marionette/test_dom_BluetoothManager.js
dom/canvas/CanvasRenderingContext2D.cpp
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLMediaElement.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/media/MediaManager.cpp
dom/permission/tests/mochitest-bt.ini
dom/permission/tests/test_bluetooth.html
dom/webidl/BluetoothAdapter.webidl
dom/webidl/BluetoothAdapterEvent.webidl
dom/webidl/BluetoothAttributeEvent.webidl
dom/webidl/BluetoothClassOfDevice.webidl
dom/webidl/BluetoothDevice.webidl
dom/webidl/BluetoothDeviceEvent.webidl
dom/webidl/BluetoothDiscoveryHandle.webidl
dom/webidl/BluetoothGatt.webidl
dom/webidl/BluetoothGattAttributeEvent.webidl
dom/webidl/BluetoothGattCharacteristic.webidl
dom/webidl/BluetoothGattCharacteristicEvent.webidl
dom/webidl/BluetoothGattDescriptor.webidl
dom/webidl/BluetoothGattServer.webidl
dom/webidl/BluetoothGattService.webidl
dom/webidl/BluetoothLeDeviceEvent.webidl
dom/webidl/BluetoothManager.webidl
dom/webidl/BluetoothMapFolderListingEvent.webidl
dom/webidl/BluetoothMapGetMessageEvent.webidl
dom/webidl/BluetoothMapMessageUpdateEvent.webidl
dom/webidl/BluetoothMapMessagesListingEvent.webidl
dom/webidl/BluetoothMapParameters.webidl
dom/webidl/BluetoothMapRequestHandle.webidl
dom/webidl/BluetoothMapSendMessageEvent.webidl
dom/webidl/BluetoothMapSetMessageStatusEvent.webidl
dom/webidl/BluetoothObexAuthEvent.webidl
dom/webidl/BluetoothObexAuthHandle.webidl
dom/webidl/BluetoothPairingEvent.webidl
dom/webidl/BluetoothPairingHandle.webidl
dom/webidl/BluetoothPairingListener.webidl
dom/webidl/BluetoothPbapParameters.webidl
dom/webidl/BluetoothPbapRequestHandle.webidl
dom/webidl/BluetoothPhonebookPullingEvent.webidl
dom/webidl/BluetoothStatusChangedEvent.webidl
dom/webidl/BluetoothUUID.webidl
dom/webidl/BluetoothVCardListingEvent.webidl
dom/webidl/BluetoothVCardPullingEvent.webidl
dom/webidl/moz.build
gfx/thebes/gfxPlatform.cpp
js/src/jit/MIR.h
layout/build/nsLayoutStatics.cpp
modules/libpref/init/all.js
netwerk/build/nsNetModule.cpp
netwerk/dns/DNS.cpp
testing/web-platform/meta/MANIFEST.json
toolkit/components/extensions/test/mochitest/mochitest.ini
toolkit/components/telemetry/Histograms.json
toolkit/mozapps/extensions/internal/XPIProvider.jsm
tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js
tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js
tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js
tools/lint/eslint/eslint-plugin-mozilla/package.json
--- a/Makefile.in
+++ b/Makefile.in
@@ -277,18 +277,18 @@ else
 DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
 endif
 # PDB files don't get moved to dist, so we need to scan the whole objdir
 MAKE_SYM_STORE_PATH := .
 endif
 ifeq ($(OS_ARCH),Darwin)
 # need to pass arch flags for universal builds
 ifdef UNIVERSAL_BINARY
-MAKE_SYM_STORE_ARGS := -c -a 'i386 x86_64' --vcs-info
-MAKE_SYM_STORE_PATH := $(DIST)/universal
+MAKE_SYM_STORE_ARGS := -c --vcs-info
+MAKE_SYM_STORE_PATH := $(DIST)/bin $(UNIFY_DIST)/bin
 else
 MAKE_SYM_STORE_ARGS := -c -a $(OS_TEST) --vcs-info
 MAKE_SYM_STORE_PATH := $(DIST)/bin
 endif
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 endif
 ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
 MAKE_SYM_STORE_ARGS := -c --vcs-info
--- a/accessible/ipc/win/moz.build
+++ b/accessible/ipc/win/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-DIRS += ['typelib']
+if CONFIG['COMPILE_ENVIRONMENT']:
+    DIRS += ['typelib']
 
 # With --disable-accessibility, we need to compile PDocAccessible.ipdl (which
 # also depends on COMPtrTypes.h), but not the C++.
 IPDL_SOURCES += ['PDocAccessible.ipdl']
 EXPORTS.mozilla.a11y += ['COMPtrTypes.h']
 
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -995,23 +995,16 @@ pref("dom.webnotifications.serviceworker
 #endif
 
 // Retain at most 10 processes' layers buffers
 pref("layers.compositor-lru-size", 10);
 
 // In B2G by deafult any AudioChannelAgent is muted when created.
 pref("dom.audiochannel.mutedByDefault", true);
 
-// The app origin of bluetooth app, which is responsible for listening pairing
-// requests.
-pref("dom.bluetooth.app-origin", "app://bluetooth.gaiamobile.org");
-
-// Enable W3C WebBluetooth API and disable B2G only GATT client API.
-pref("dom.bluetooth.webbluetooth.enabled", false);
-
 // Default device name for Presentation API
 pref("dom.presentation.device.name", "Firefox OS");
 
 // Enable notification of performance timing
 pref("dom.performance.enable_notify_performance_timing", true);
 
 // Multi-screen
 pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html");
--- a/b2g/common.configure
+++ b/b2g/common.configure
@@ -4,16 +4,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/.
 
 # Truetype fonts for B2G
 # ==============================================================
 option(env='MOZTTDIR', nargs=1, help='Path to truetype fonts for B2G')
 
 @depends('MOZTTDIR')
+@imports('os')
 def mozttdir(value):
     if value:
         path = value[0]
         if not os.path.isdir(path):
             die('MOZTTDIR "%s" is not a valid directory', path)
         return path
 
 set_config('MOZTTDIR', mozttdir)
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -155,19 +155,16 @@
 @RESPATH@/components/dom_workers.xpt
 #ifdef MOZ_WIDGET_GONK
 @RESPATH@/components/dom_wifi.xpt
 @RESPATH@/components/dom_system_gonk.xpt
 #endif
 #ifdef MOZ_B2G_RIL
 @RESPATH@/components/dom_mobileconnection.xpt
 #endif
-#ifdef MOZ_B2G_BT
-@RESPATH@/components/dom_bluetooth.xpt
-#endif
 @RESPATH@/components/dom_canvas.xpt
 @RESPATH@/components/dom_contacts.xpt
 @RESPATH@/components/dom_core.xpt
 @RESPATH@/components/dom_css.xpt
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<blocklist lastupdate="1477919228776" xmlns="http://www.mozilla.org/2006/addons-blocklist">
+<blocklist lastupdate="1478088426949" xmlns="http://www.mozilla.org/2006/addons-blocklist">
   <emItems>
     <emItem blockID="i988" id="{b12785f5-d8d0-4530-a3ea-5c4263b85bef}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i398" id="{377e5d4d-77e5-476a-8716-7e70a9272da0}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
@@ -140,28 +140,28 @@
     <emItem blockID="i537" id="rally_toolbar_ff@bulletmedia.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i1266" id="@stopad">
       <prefs/>
       <versionRange minVersion="0" maxVersion="0.0.4" severity="1"/>
     </emItem>
+    <emItem blockID="i473" id="{81b13b5d-fba1-49fd-9a6b-189483ac548a}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i914" id="{0153E448-190B-4987-BDE1-F256CADA672F}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="39.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i473" id="{81b13b5d-fba1-49fd-9a6b-189483ac548a}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i496" id="{ACAA314B-EEBA-48e4-AD47-84E31C44796C}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i690" id="{55dce8ba-9dec-4013-937e-adbf9317d990">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -326,38 +326,38 @@
     <emItem blockID="i1261" id="support@lastpass.com">
       <prefs/>
       <versionRange minVersion="4.0.0a" maxVersion="4.1.20a" severity="1"/>
     </emItem>
     <emItem blockID="i447" id="{B18B1E5C-4D81-11E1-9C00-AFEB4824019B}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i509" id="contato@facefollow.net">
+    <emItem blockID="i394" id="{7D4F1959-3F72-49d5-8E59-F02F8AA6815D}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i394" id="{7D4F1959-3F72-49d5-8E59-F02F8AA6815D}">
+    <emItem blockID="i509" id="contato@facefollow.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i810" id="{41339ee8-61ed-489d-b049-01e41fd5d7e0}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i618" id="toolbar@ask.com">
       <prefs/>
       <versionRange minVersion="3.15.24" maxVersion="3.15.24.*" severity="1"/>
       <versionRange minVersion="3.15.13" maxVersion="3.15.13.*" severity="1"/>
       <versionRange minVersion="3.15.28" maxVersion="3.15.28.*" severity="1"/>
       <versionRange minVersion="3.15.22" maxVersion="3.15.22.*" severity="1"/>
       <versionRange minVersion="3.15.8" maxVersion="3.15.8.*" severity="1"/>
       <versionRange minVersion="3.15.10" maxVersion="3.15.11.*" severity="1"/>
+      <versionRange minVersion="3.15.18" maxVersion="3.15.20.*" severity="1"/>
       <versionRange minVersion="3.15.5" maxVersion="3.15.5.*" severity="1"/>
-      <versionRange minVersion="3.15.18" maxVersion="3.15.20.*" severity="1"/>
       <versionRange minVersion="3.15.31" maxVersion="3.15.31.*" severity="1"/>
       <versionRange minVersion="3.15.26" maxVersion="3.15.26.*" severity="1"/>
     </emItem>
     <emItem blockID="i15" id="personas@christopher.beard">
       <prefs/>
       <versionRange minVersion="1.6" maxVersion="1.6">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="3.6.*" minVersion="3.6"/>
@@ -451,39 +451,39 @@
     <emItem blockID="i1232" id="nosquint@urandom.ca">
       <prefs/>
       <versionRange minVersion="0" maxVersion="2.1.9.1-signed.1-signed" severity="1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="47"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i650" id="jid1-qj0w91o64N7Eeg@jetpack">
-      <prefs/>
-      <versionRange minVersion="39.5.1" maxVersion="47.0.4" severity="3"/>
+    <emItem blockID="i748" id="{32da2f20-827d-40aa-a3b4-2fc4a294352e}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i544" id="/^(93abedcf-8e3a-4d02-b761-d1441e437c09@243f129d-aee2-42c2-bcd1-48858e1c22fd\.com|9acfc440-ac2d-417a-a64c-f6f14653b712@09f9a966-9258-4b12-af32-da29bdcc28c5\.com|58ad0086-1cfb-48bb-8ad2-33a8905572bc@5715d2be-69b9-4930-8f7e-64bdeb961cfd\.com)$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i748" id="{32da2f20-827d-40aa-a3b4-2fc4a294352e}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    <emItem blockID="i650" id="jid1-qj0w91o64N7Eeg@jetpack">
+      <prefs/>
+      <versionRange minVersion="39.5.1" maxVersion="47.0.4" severity="3"/>
+    </emItem>
+    <emItem blockID="i640" id="jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i628" id="ffxtlbr@iminent.com">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i640" id="jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i1228" id="unblocker30__web@unblocker.yt">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i1042" id="gjhrjenrengoe@jfdnkwelfwkm.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -520,24 +520,24 @@
     <emItem blockID="i772" id="{72b98dbc-939a-4e0e-b5a9-9fdbf75963ef}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i996" id="9598582LLKmjasieijkaslesae@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i586" id="jid1-0xtMKhXFEs4jIg@jetpack">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i88" id="anttoolbar@ant.com">
       <prefs/>
       <versionRange minVersion="2.4.6.4" maxVersion="2.4.6.4" severity="1"/>
     </emItem>
-    <emItem blockID="i586" id="jid1-0xtMKhXFEs4jIg@jetpack">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i358" id="lfind@nijadsoft.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i438" id="{02edb56b-9b33-435b-b7df-b2843273a694}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -657,43 +657,43 @@
     <emItem blockID="i1038" id="344141-fasf9jas08hasoiesj9ia8ws@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i471" id="firefox@luckyleap.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i560" id="adsremoval@adsremoval.net">
+    <emItem blockID="i396" id="/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\.com$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i396" id="/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\.com$/">
+    <emItem blockID="i560" id="adsremoval@adsremoval.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i538" id="{354dbb0a-71d5-4e9f-9c02-6c88b9d387ba}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i968" id="{184AA5E6-741D-464a-820E-94B3ABC2F3B4}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i742" id="{f894a29a-f065-40c3-bb19-da6057778493}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    <emItem blockID="i658" id="low_quality_flash@pie2k.com">
+      <prefs/>
+      <versionRange minVersion="46.2" maxVersion="47.1" severity="3"/>
     </emItem>
     <emItem blockID="i792" id="{8f894ed3-0bf2-498e-a103-27ef6e88899f}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i658" id="low_quality_flash@pie2k.com">
-      <prefs/>
-      <versionRange minVersion="46.2" maxVersion="47.1" severity="3"/>
+    <emItem blockID="i742" id="{f894a29a-f065-40c3-bb19-da6057778493}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
       <prefs/>
       <versionRange minVersion="2.2" maxVersion="2.2"/>
     </emItem>
     <emItem blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
@@ -713,17 +713,17 @@
     <emItem blockID="i352" id="vpyekkifgv@vpyekkifgv.org">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i256" id="/^[0-9a-f]+@[0-9a-f]+\.info/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i1278" id="dodatek@firefox.pl">
+    <emItem blockID="i1278" id="/^(ff\-)?dodate(kKKK|XkKKK|k|kk|kkx|kR)@(firefox|flash(1)?)\.pl|dode(ee)?k@firefoxnet\.pl$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i980" id="wHO@W9.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i127" id="plugin@youtubeplayer.com">
@@ -745,24 +745,24 @@
     <emItem blockID="i380" id="{cc8f597b-0765-404e-a575-82aefbd81daf}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i432" id="lugcla21@gmail.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i392" id="{EEE6C361-6118-11DC-9C72-001320C79847}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i724" id="{1cdbda58-45f8-4d91-b566-8edce18f8d0a}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i392" id="{EEE6C361-6118-11DC-9C72-001320C79847}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i429" id="{B40794A0-7477-4335-95C5-8CB9BBC5C4A5}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i638" id="{7b1bf0b6-a1b9-42b0-b75d-252036438bdc}">
       <prefs/>
       <versionRange minVersion="27.8" maxVersion="27.9" severity="3"/>
     </emItem>
@@ -809,24 +809,24 @@
     <emItem blockID="i434" id="afurladvisor@anchorfree.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i872" id="search-snacks@search-snacks.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i90" id="videoplugin@player.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*"/>
+    </emItem>
     <emItem blockID="i306" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE10}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i90" id="videoplugin@player.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*"/>
-    </emItem>
     <emItem blockID="i966" id="{5C655500-E712-41e7-9349-CE462F844B19}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.0.1-signed" severity="1"/>
     </emItem>
     <emItem blockID="i1012" id="wxtui502n2xce9j@no14">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -895,41 +895,41 @@
     <emItem blockID="i1264" id="suchpony@suchpony.de">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.6.7" severity="3"/>
     </emItem>
     <emItem blockID="i476" id="mbroctone@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i722" id="{9802047e-5a84-4da3-b103-c55995d147d1}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i656" id="hdv@vovcacik.addons.mozilla.org">
       <prefs/>
       <versionRange minVersion="102.0" maxVersion="102.0" severity="3"/>
     </emItem>
-    <emItem blockID="i722" id="{9802047e-5a84-4da3-b103-c55995d147d1}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i228" id="crossriderapp5060@crossrider.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i470" id="extension@FastFreeConverter.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i478" id="{7e8a1050-cf67-4575-92df-dcc60e7d952d}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i1223" id="tmbepff@trendmicro.com">
       <prefs/>
       <versionRange minVersion="9.2" maxVersion="9.2.0.1023" severity="1"/>
       <versionRange minVersion="0" maxVersion="9.1.0.1035" severity="1"/>
     </emItem>
-    <emItem blockID="i478" id="{7e8a1050-cf67-4575-92df-dcc60e7d952d}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i370" id="happylyrics@hpyproductions.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i440" id="{2d069a16-fca1-4e81-81ea-5d5086dcbd0c}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -993,24 +993,24 @@
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i505" id="extacylife@a.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i1414" id="new@kuot.pro">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i528" id="008abed2-b43a-46c9-9a5b-a771c87b82da@1ad61d53-2bdc-4484-a26b-b888ecae1906.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i1414" id="/^new@kuot\.pro|{13ec6687-0b15-4f01-a5a0-7a891c18e4ee}|rebeccahoppkins(ty(tr)?)?@gmail\.com|{501815af-725e-45be-b0f2-8f36f5617afc}|{9bdb5f1f-b1e1-4a75-be31-bdcaace20a99}|{e9d93e1d-792f-4f95-b738-7adb0e853b7b}|dojadewaskurwa@gmail\.com$/">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i712" id="{a2bfe612-4cf5-48ea-907c-f3fb25bc9d6b}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i652" id="garg_sms@yahoo.in">
       <prefs/>
       <versionRange minVersion="67.9" maxVersion="67.9" severity="3"/>
     </emItem>
@@ -1064,66 +1064,66 @@
     <emItem blockID="i350" id="sqlmoz@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i446" id="{E90FA778-C2B7-41D0-9FA9-3FEC1CA54D66}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i117" id="{ce7e73df-6a44-4028-8079-5927a588c948}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="1.0.8" severity="1"/>
+    </emItem>
+    <emItem blockID="i13" id="{E8E88AB0-7182-11DF-904E-6045E0D72085}">
+      <prefs/>
+    </emItem>
     <emItem blockID="i226" id="{462be121-2b54-4218-bf00-b9bf8135b23f}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i13" id="{E8E88AB0-7182-11DF-904E-6045E0D72085}">
-      <prefs/>
-    </emItem>
-    <emItem blockID="i117" id="{ce7e73df-6a44-4028-8079-5927a588c948}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="1.0.8" severity="1"/>
-    </emItem>
     <emItem blockID="i258" id="helperbar@helperbar.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.0" severity="1"/>
     </emItem>
     <emItem blockID="i96" id="youtubeee@youtuber3.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
     <emItem blockID="i44" id="sigma@labs.mozilla">
       <prefs/>
     </emItem>
     <emItem blockID="i564" id="/^(firefox@vebergreat\.net|EFGLQA@78ETGYN-0W7FN789T87\.COM)$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i500" id="{2aab351c-ad56-444c-b935-38bffe18ad26}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i97" id="support3_en@adobe122.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
-    <emItem blockID="i500" id="{2aab351c-ad56-444c-b935-38bffe18ad26}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i439" id="{d2cf9842-af95-48cd-b873-bfbb48cd7f5e}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i576" id="newmoz@facebook.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
       <prefs/>
       <versionRange minVersion="0.1" maxVersion="*">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="9.0" minVersion="9.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
+    <emItem blockID="i576" id="newmoz@facebook.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i776" id="g@uzcERQ6ko.net">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i494" id="/^({e9df9360-97f8-4690-afe6-996c80790da4}|{687578b9-7132-4a7a-80e4-30ee31099e03}|{46a3135d-3683-48cf-b94c-82655cbc0e8a}|{49c795c2-604a-4d18-aeb1-b3eba27e5ea2}|{7473b6bd-4691-4744-a82b-7854eb3d70b6}|{96f454ea-9d38-474f-b504-56193e00c1a5})$/">
@@ -1359,36 +1359,36 @@
     <emItem blockID="i1034" id="a88a77ahjjfjakckmmabsy278djasi@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i562" id="iobitapps@mybrowserbar.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i430" id="1chtw@facebook.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i338" id="{1FD91A9C-410C-4090-BBCC-55D3450EF433}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i916" id="{97E22097-9A2F-45b1-8DAF-36AD648C7EF4}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="39.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
     <emItem blockID="i970" id="hha8771ui3-Fo9j9h7aH98jsdfa8sda@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i430" id="1chtw@facebook.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i344" id="lrcsTube@hansanddeta.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i79" id="GifBlock@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
@@ -1445,24 +1445,24 @@
     <emItem blockID="i58" id="webmaster@buzzzzvideos.info">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
     <emItem blockID="i5" id="support@daemon-tools.cc">
       <prefs/>
       <versionRange minVersion=" " maxVersion="1.0.0.5"/>
     </emItem>
+    <emItem blockID="i449" id="gystqfr@ylgga.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i378" id="{a7aae4f0-bc2e-a0dd-fb8d-68ce32c9261f}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i449" id="gystqfr@ylgga.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i545" id="superlrcs@svenyor.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i163" id="info@allpremiumplay.info">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -1682,21 +1682,21 @@
     <emItem blockID="i519" id="703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i477" id="mbrnovone@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i836" id="hansin@topvest.id">
+    <emItem blockID="i495" id="kallow@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i495" id="kallow@facebook.com">
+    <emItem blockID="i836" id="hansin@topvest.id">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i542" id="/^({bf67a47c-ea97-4caf-a5e3-feeba5331231}|{24a0cfe1-f479-4b19-b627-a96bf1ea3a56})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i286" id="{58bd07eb-0ee0-4df0-8121-dc9b693373df}">
@@ -1796,28 +1796,28 @@
     <emItem blockID="i926" id="{B1FC07E1-E05B-4567-8891-E63FBE545BA8}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="39.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i782" id="safebrowse@safebrowse.co">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i806" id="{d9284e50-81fc-11da-a72b-0800200c9a66}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="7.7.34" severity="1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="34.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
+    <emItem blockID="i782" id="safebrowse@safebrowse.co">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i382" id="{6926c7f7-6006-42d1-b046-eba1b3010315}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i812" id="{1e4ea5fc-09e5-4f45-a43b-c048304899fc}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -1896,28 +1896,28 @@
     <emItem blockID="i1214" id="firefoxdav@icloud.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.4.22" severity="1"/>
     </emItem>
     <emItem blockID="i808" id="{c96d1ae6-c4cf-4984-b110-f5f561b33b5a}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i66" id="youtubeer@youtuber.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*"/>
+    </emItem>
     <emItem blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
       <prefs/>
       <versionRange minVersion="1.2" maxVersion="1.2">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="3.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i66" id="youtubeer@youtuber.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*"/>
-    </emItem>
     <emItem blockID="i517" id="/^({16e193c8-1706-40bf-b6f3-91403a9a22be}|{284fed43-2e13-4afe-8aeb-50827d510e20}|{5e3cc5d8-ed11-4bed-bc47-35b4c4bc1033}|{7429e64a-1fd4-4112-a186-2b5630816b91}|{8c9980d7-0f09-4459-9197-99b3e559660c}|{8f1d9545-0bb9-4583-bb3c-5e1ac1e2920c})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i460" id="{845cab51-d8d2-472f-8bd9-2b44642d97c2}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
new file mode 100644
--- /dev/null
+++ b/browser/base/.eslintrc.js
@@ -0,0 +1,11 @@
+"use strict";
+
+module.exports = {
+  "rules": {
+    "no-unused-vars": ["error", {
+      "vars": "local",
+      "varsIgnorePattern": "^Cc|Ci|Cu|Cr|EXPORTED_SYMBOLS",
+      "args": "none",
+    }]
+  }
+};
--- a/browser/base/content/aboutDialog-appUpdater.js
+++ b/browser/base/content/aboutDialog-appUpdater.js
@@ -361,17 +361,16 @@ appUpdater.prototype =
       break;
     case Components.results.NS_BINDING_ABORTED:
       // Do not remove UI listener since the user may resume downloading again.
       break;
     case Components.results.NS_OK:
       this.removeDownloadListener();
       if (this.backgroundUpdateEnabled) {
         this.selectPanel("applying");
-        let update = this.um.activeUpdate;
         let self = this;
         Services.obs.addObserver(function (aSubject, aTopic, aData) {
           // Update the UI when the background updater is finished
           let status = aData;
           if (status == "applied" || status == "applied-service" ||
               status == "pending" || status == "pending-service" ||
               status == "pending-elevate") {
             // If the update is successfully applied, or if the updater has
--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -64,17 +64,17 @@ var gDataNotificationInfoBar = {
       popup: null,
       callback: () => {
         this._actionTaken = true;
         window.openAdvancedPreferences("dataChoicesTab");
       },
     }];
 
     this._log.info("Creating data reporting policy notification.");
-    let notification = this._notificationBox.appendNotification(
+    this._notificationBox.appendNotification(
       message,
       this._DATA_REPORTING_NOTIFICATION,
       null,
       this._notificationBox.PRIORITY_INFO_HIGH,
       buttons,
       event => {
         if (event == "removed") {
           Services.obs.notifyObservers(null, "datareporting:notify-data-policy:close", null);
@@ -120,9 +120,8 @@ var gDataNotificationInfoBar = {
     }
   },
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference,
   ]),
 };
-
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -747,19 +747,16 @@ HistoryMenu.prototype = {
   },
 
   /**
    * Populate when the history menu is opened
    */
   populateUndoWindowSubmenu: function PHM_populateUndoWindowSubmenu() {
     let undoMenu = this._rootElt.getElementsByClassName("recentlyClosedWindowsMenu")[0];
     let undoPopup = undoMenu.firstChild;
-    let menuLabelString = gNavigatorBundle.getString("menuUndoCloseWindowLabel");
-    let menuLabelStringSingleTab =
-      gNavigatorBundle.getString("menuUndoCloseWindowSingleTabLabel");
 
     // remove existing menu items
     while (undoPopup.hasChildNodes())
       undoPopup.removeChild(undoPopup.firstChild);
 
     // no restorable windows, so make sure menu is disabled, and return
     if (SessionStore.getClosedWindowCount() == 0) {
       undoMenu.setAttribute("disabled", true);
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -190,17 +190,16 @@ var gPluginHandler = {
         aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
         break;
       default:
         Cu.reportError(Error("Unexpected plugin state: " + aNewState));
         return;
     }
 
     let browser = aNotification.browser;
-    let contentWindow = browser.contentWindow;
     if (aNewState != "continue") {
       let principal = aNotification.options.principal;
       Services.perms.addFromPrincipal(principal, aPluginInfo.permissionString,
                                       permission, expireType, expireTime);
       aPluginInfo.pluginPermissionType = expireType;
     }
 
     browser.messageManager.sendAsyncMessage("BrowserPlugins:ActivatePlugins", {
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -436,20 +436,16 @@ var gSyncUI = {
       dateFormat = {month: 'long', day: 'numeric'};
     } else {
       dateFormat = {weekday: 'long', hour: 'numeric', minute: 'numeric'};
     }
     let lastSyncDateString = date.toLocaleDateString(undefined, dateFormat);
     return this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDateString], 1);
   },
 
-  onSyncFinish: function SUI_onSyncFinish() {
-    let title = this._stringBundle.GetStringFromName("error.sync.title");
-  },
-
   onClientsSynced: function() {
     let broadcaster = document.getElementById("sync-syncnow-state");
     if (broadcaster) {
       if (Weave.Service.clientsEngine.stats.numClients > 1) {
         broadcaster.setAttribute("devices-status", "multi");
       } else {
         broadcaster.setAttribute("devices-status", "single");
       }
@@ -479,17 +475,17 @@ var gSyncUI = {
       case "weave:service:sync:error":
         this.onActivityStop();
         break;
     }
     // Now non-activity state (eg, enabled, errors, etc)
     // Note that sync uses the ":ui:" notifications for errors because sync.
     switch (topic) {
       case "weave:ui:sync:finish":
-        this.onSyncFinish();
+        // Do nothing.
         break;
       case "weave:ui:sync:error":
       case "weave:service:setup-complete":
       case "weave:service:login:finish":
       case "weave:service:login:start":
       case "weave:service:start-over":
         this.updateUI();
         break;
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -111,18 +111,16 @@ var TabsInTitlebar = {
 
     // In some edgecases it is possible for this to fire before we've initialized.
     // Don't run now, but don't forget to run it when we do initialize.
     if (!this._initialized) {
       this._updateOnInit = true;
       return;
     }
 
-    let allowed = true;
-
     if (!aForce) {
       // _update is called on resize events, because the window is not ready
       // after sizemode events. However, we only care about the event when the
       // sizemode is different from the last time we updated the appearance of
       // the tabs in the titlebar.
       let sizemode = document.documentElement.getAttribute("sizemode");
       if (this._lastSizeMode == sizemode) {
         return;
@@ -133,20 +131,17 @@ var TabsInTitlebar = {
       // still changing in the consequent "fullscreen" event. Code there will
       // call this function again when everything is ready.
       // See browser-fullScreen.js: FullScreen.toggle and bug 1173768.
       if (oldSizeMode == "fullscreen") {
         return;
       }
     }
 
-    for (let something in this._disallowed) {
-      allowed = false;
-      break;
-    }
+    let allowed = (Object.keys(this._disallowed)).length == 0;
 
     let titlebar = $("titlebar");
     let titlebarContent = $("titlebar-content");
     let menubar = $("toolbar-menubar");
 
     if (allowed) {
       // We set the tabsintitlebar attribute first so that our CSS for
       // tabsintitlebar manifests before we do our measurements.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -45,16 +45,17 @@ Cu.import("resource://gre/modules/Notifi
   ["SimpleServiceDiscovery", "resource://gre/modules/SimpleServiceDiscovery.jsm"],
   ["SitePermissions", "resource:///modules/SitePermissions.jsm"],
   ["Social", "resource:///modules/Social.jsm"],
   ["TabCrashHandler", "resource:///modules/ContentCrashHandlers.jsm"],
   ["Task", "resource://gre/modules/Task.jsm"],
   ["TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm"],
   ["Translation", "resource:///modules/translation/Translation.jsm"],
   ["UITour", "resource:///modules/UITour.jsm"],
+  ["URLBarZoom", "resource:///modules/URLBarZoom.jsm"],
   ["UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"],
   ["Weave", "resource://services-sync/main.js"],
   ["fxAccounts", "resource://gre/modules/FxAccounts.jsm"],
   ["gDevTools", "resource://devtools/client/framework/gDevTools.jsm"],
   ["gDevToolsBrowser", "resource://devtools/client/framework/gDevTools.jsm"],
   ["webrtcUI", "resource:///modules/webrtcUI.jsm", ]
 ].forEach(([name, resource]) => XPCOMUtils.defineLazyModuleGetter(this, name, resource));
 
@@ -616,17 +617,17 @@ var gPopupBlockerObserver = {
     var target = aEvent.target;
     var popupReportIndex = target.getAttribute("popupReportIndex");
     let browser = target.popupReportBrowser;
     browser.unblockPopup(popupReportIndex);
   },
 
   showAllBlockedPopups: function (aBrowser)
   {
-    let popups = aBrowser.retrieveListOfBlockedPopups().then(popups => {
+    aBrowser.retrieveListOfBlockedPopups().then(popups => {
       for (let i = 0; i < popups.length; i++) {
         if (popups[i].popupWindowURIspec)
           aBrowser.unblockPopup(i);
       }
     }, null);
   },
 
   editPopupSettings: function ()
@@ -791,17 +792,16 @@ function gKeywordURIFixup({ target: brow
 function _loadURIWithFlags(browser, uri, params) {
   if (!uri) {
     uri = "about:blank";
   }
   let flags = params.flags || 0;
   let referrer = params.referrerURI;
   let referrerPolicy = ('referrerPolicy' in params ? params.referrerPolicy :
                         Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT);
-  let charset = params.charset;
   let postData = params.postData;
 
   let wasRemote = browser.isRemoteBrowser;
 
   let process = browser.isRemoteBrowser ? Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT
                                         : Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
   let mustChangeProcess = gMultiProcessBrowser &&
                           !E10SUtils.canLoadURIInProcess(uri, process);
@@ -3099,17 +3099,16 @@ function mirrorMenuItemClicked(event) {
                                                            {service: event.originalTarget._service});
 }
 
 function populateMirrorTabMenu(popup) {
   popup.innerHTML = null;
   if (!Services.prefs.getBoolPref("browser.casting.enabled")) {
     return;
   }
-  let videoEl = this.target;
   let doc = popup.ownerDocument;
   let services = CastingApps.getServicesForMirroring();
   services.forEach(service => {
     let item = doc.createElement("menuitem");
     item.setAttribute("label", service.friendlyName);
     item._service = service;
     item.addEventListener("command", mirrorMenuItemClicked);
     popup.appendChild(item);
@@ -4444,26 +4443,23 @@ var XULBrowserWindow = {
           location == "") {  // Second condition is for new tabs, otherwise
                              // reload function is enabled until tab is refreshed.
         this.reloadCommand.setAttribute("disabled", "true");
       } else {
         this.reloadCommand.removeAttribute("disabled");
       }
 
       URLBarSetURI(aLocationURI);
-
       BookmarkingUI.onLocationChange();
-
       gIdentityHandler.onLocationChange();
-
       SocialUI.updateState();
-
       UITour.onLocationChange(location);
-
       gTabletModePageCounter.inc();
+      ReaderParent.updateReaderButton(gBrowser.selectedBrowser);
+      URLBarZoom.updateZoomButton(gBrowser.selectedBrowser, "browser-fullZoom:location-change");
 
       // Utility functions for disabling find
       var shouldDisableFind = function shouldDisableFind(aDocument) {
         let docElt = aDocument.documentElement;
         return docElt && docElt.getAttribute("disablefastfind") == "true";
       }
 
       var disableFindCommands = function disableFindCommands(aDisable) {
@@ -4507,17 +4503,16 @@ var XULBrowserWindow = {
           gBrowser.selectedTab.hasAttribute("customizemode")) {
         gCustomizeMode.enter();
       } else if (CustomizationHandler.isEnteringCustomizeMode ||
                  CustomizationHandler.isCustomizing()) {
         gCustomizeMode.exit();
       }
     }
     UpdateBackForwardCommands(gBrowser.webNavigation);
-    ReaderParent.updateReaderButton(gBrowser.selectedBrowser);
 
     gGestureSupport.restoreRotationState();
 
     // See bug 358202, when tabs are switched during a drag operation,
     // timers don't fire on windows (bug 203573)
     if (aRequest)
       setTimeout(function () { XULBrowserWindow.asyncUpdateUI(); }, 0);
     else
@@ -5630,17 +5625,17 @@ function handleDroppedLink(event, urlOrL
   let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
 
   let userContextId = gBrowser.selectedBrowser.getAttribute("usercontextid");
 
   // event is null if links are dropped in content process.
   // inBackground should be false, as it's loading into current browser.
   let inBackground = false;
   if (event) {
-    let inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
+    inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
     if (event.shiftKey)
       inBackground = !inBackground;
   }
 
   Task.spawn(function*() {
     let urls = [];
     let postDatas = [];
     for (let link of links) {
--- a/browser/base/content/contentSearchUI.js
+++ b/browser/base/content/contentSearchUI.js
@@ -4,17 +4,16 @@
 
 "use strict";
 
 this.ContentSearchUIController = (function () {
 
 const MAX_DISPLAYED_SUGGESTIONS = 6;
 const SUGGESTION_ID_PREFIX = "searchSuggestion";
 const ONE_OFF_ID_PREFIX = "oneOff";
-const CSS_URI = "chrome://browser/content/contentSearchUI.css";
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 
 /**
  * Creates a new object that manages search suggestions and their UI for a text
  * box.
  *
  * The UI consists of an html:table that's inserted into the DOM after the given
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -819,17 +819,16 @@ function onImageSelect()
     tree.flex = 0;
     makePreview(getSelectedRows(tree)[0]);
   }
 }
 
 // Makes the media preview (image, video, etc) for the selected row on the media tab.
 function makePreview(row)
 {
-  var imageTree = document.getElementById("imagetree");
   var item = gImageView.data[row][COL_IMAGE_NODE];
   var url = gImageView.data[row][COL_IMAGE_ADDRESS];
   var isBG = gImageView.data[row][COL_IMAGE_BG];
   var isAudio = false;
 
   setItemValue("imageurltext", url);
   setItemValue("imagetext", item.imageText);
   setItemValue("imagelongdesctext", item.longDesc);
@@ -1010,17 +1009,16 @@ var imagePermissionObserver = {
     if (document.getElementById("mediaPreviewBox").collapsed)
       return;
 
     if (aTopic == "perm-changed") {
       var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
       if (permission.type == "image") {
         var imageTree = document.getElementById("imagetree");
         var row = getSelectedRow(imageTree);
-        var item = gImageView.data[row][COL_IMAGE_NODE];
         var url = gImageView.data[row][COL_IMAGE_ADDRESS];
         if (permission.matchesURI(makeURI(url), true)) {
           makeBlockImage(url);
         }
       }
     }
   }
 }
--- a/browser/base/content/pageinfo/security.js
+++ b/browser/base/content/pageinfo/security.js
@@ -16,19 +16,16 @@ var security = {
 
   // Display the server certificate (static)
   viewCert : function () {
     var cert = security._cert;
     viewCertHelper(window, cert);
   },
 
   _getSecurityInfo : function() {
-    const nsIX509Cert = Components.interfaces.nsIX509Cert;
-    const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
-    const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
     const nsISSLStatusProvider = Components.interfaces.nsISSLStatusProvider;
     const nsISSLStatus = Components.interfaces.nsISSLStatus;
 
     // We don't have separate info for a frame, return null until further notice
     // (see bug 138479)
     if (!this.windowInfo.isTopWindow)
       return null;
 
--- a/browser/base/content/safeMode.js
+++ b/browser/base/content/safeMode.js
@@ -60,17 +60,16 @@ function onExtra1() {
     return true;
   }
   // The reset dialog will handle starting the reset process if the user confirms.
   showResetDialog();
   return false;
 }
 
 function onLoad() {
-  let dialog = document.documentElement;
   if (appStartup.automaticSafeModeNecessary) {
     document.getElementById("autoSafeMode").hidden = false;
     document.getElementById("safeMode").hidden = true;
     if (ResetProfile.resetSupported()) {
       document.getElementById("resetProfile").hidden = false;
     } else {
       // Hide the reset button is it's not supported.
       document.documentElement.getButton("extra1").hidden = true;
--- a/browser/base/content/sync/aboutSyncTabs.js
+++ b/browser/base/content/sync/aboutSyncTabs.js
@@ -206,17 +206,17 @@ var RemoteTabViewer = {
 
   _generateWeaveTabList: function () {
     let engine = Weave.Service.engineManager.get("tabs");
     let list = this._tabsList;
 
     let seenURLs = new Set();
     let localURLs = engine.getOpenURLs();
 
-    for (let [guid, client] of Object.entries(engine.getAllClients())) {
+    for (let [, client] of Object.entries(engine.getAllClients())) {
       // Create the client node, but don't add it in-case we don't show any tabs
       let appendClient = true;
 
       client.tabs.forEach(function({title, urlHistory, icon}) {
         let url = urlHistory[0];
         if (!url || localURLs.has(url) || seenURLs.has(url)) {
           return;
         }
--- a/browser/base/content/sync/genericChange.js
+++ b/browser/base/content/sync/genericChange.js
@@ -27,17 +27,16 @@ var Change = {
 
   get _updatingPassphrase() {
     return this._dialogType == "UpdatePassphrase";
   },
 
   onLoad: function Change_onLoad() {
     /* Load labels */
     let introText = document.getElementById("introText");
-    let introText2 = document.getElementById("introText2");
     let warningText = document.getElementById("warningText");
 
     // load some other elements & info from the window
     this._dialog = document.getElementById("change-dialog");
     this._dialogType = window.arguments[0];
     this._duringSetup = window.arguments[1];
     this._status = document.getElementById("status");
     this._statusIcon = document.getElementById("statusIcon");
--- a/browser/base/content/sync/setup.js
+++ b/browser/base/content/sync/setup.js
@@ -792,17 +792,16 @@ var gSyncSetup = {
     }, 1000);
   },
 
   checkServer: function () {
     delete this._checkServerTimer;
     let el = document.getElementById("server");
     let valid = false;
     let feedback = document.getElementById("serverFeedbackRow");
-    let str = "";
     if (el.value) {
       valid = this._validateServer(el);
       let str = valid ? "" : "serverInvalid.label";
       this._setFeedbackMessage(feedback, valid, str);
     }
     else
       this._setFeedbackMessage(feedback, true);
 
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -267,17 +267,16 @@ var AboutReaderListener = {
     addEventListener("pagehide", this, false);
     addMessageListener("Reader:ToggleReaderMode", this);
     addMessageListener("Reader:PushState", this);
   },
 
   receiveMessage: function(message) {
     switch (message.name) {
       case "Reader:ToggleReaderMode":
-        let url = content.document.location.href;
         if (!this.isAboutReader) {
           this._articlePromise = ReaderMode.parseDocument(content.document).catch(Cu.reportError);
           ReaderMode.enterReaderMode(docShell, content);
         } else {
           this._isLeavingReaderMode = true;
           ReaderMode.leaveReaderMode(docShell, content);
         }
         break;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1761,17 +1761,17 @@
 
             // Restore the securityUI state.
             let securityUI = aBrowser.securityUI;
             let state = securityUI ? securityUI.state
                                    : Ci.nsIWebProgressListener.STATE_IS_INSECURE;
             // Include the true final argument to indicate that this event is
             // simulated (instead of being observed by the webProgressListener).
             this._callProgressListeners(aBrowser, "onSecurityChange",
-                                        [aBrowser.webProgress, null, securityUI.state, true],
+                                        [aBrowser.webProgress, null, state, true],
                                         true, false);
 
             if (aShouldBeRemote) {
               // Switching the browser to be remote will connect to a new child
               // process so the browser can no longer be considered to be
               // crashed.
               tab.removeAttribute("crashed");
             } else {
@@ -3783,17 +3783,17 @@
             },
 
             // This function runs before every event. It fixes up the state
             // to account for closed tabs.
             preActions: function() {
               this.assert(this.tabbrowser._switcher);
               this.assert(this.tabbrowser._switcher === this);
 
-              for (let [tab, state] of this.tabState) {
+              for (let [tab, ] of this.tabState) {
                 if (!tab.linkedBrowser) {
                   this.tabState.delete(tab);
                 }
               }
 
               if (this.lastVisibleTab && !this.lastVisibleTab.linkedBrowser) {
                 this.lastVisibleTab = null;
               }
@@ -4742,17 +4742,16 @@
               this._findAsYouType = Services.prefs.getBoolPref("accessibility.typeaheadfind");
               break;
           }
         ]]></body>
       </method>
 
       <constructor>
         <![CDATA[
-          let browserStack = document.getAnonymousElementByAttribute(this, "anonid", "browserStack");
           this.mCurrentBrowser = document.getAnonymousElementByAttribute(this, "anonid", "initialBrowser");
           this.mCurrentBrowser.permanentKey = {};
 
           Services.obs.addObserver(this, "live-resize-start", false);
           Services.obs.addObserver(this, "live-resize-end", false);
 
           this.mCurrentTab = this.tabContainer.firstChild;
           const nsIEventListenerService =
@@ -5072,38 +5071,52 @@
           var browser = event.originalTarget;
           var tab = this.getTabForBrowser(browser);
           if (!tab)
             return;
 
           clearTimeout(tab._soundPlayingAttrRemovalTimer);
           tab._soundPlayingAttrRemovalTimer = 0;
 
+          let modifiedAttrs = [];
+          if (tab.hasAttribute("soundplaying-scheduledremoval")) {
+            tab.removeAttribute("soundplaying-scheduledremoval");
+            modifiedAttrs.push("soundplaying-scheduledremoval");
+          }
+
           if (!tab.hasAttribute("soundplaying")) {
             tab.setAttribute("soundplaying", true);
-            this._tabAttrModified(tab, ["soundplaying"]);
+            modifiedAttrs.push("soundplaying");
           }
+
+          this._tabAttrModified(tab, modifiedAttrs);
         ]]>
       </handler>
       <handler event="DOMAudioPlaybackStopped">
         <![CDATA[
           if (!Services.prefs.getBoolPref("browser.tabs.showAudioPlayingIcon") ||
               !event.isTrusted)
             return;
 
           var browser = event.originalTarget;
           var tab = this.getTabForBrowser(browser);
           if (!tab)
             return;
 
           if (tab.hasAttribute("soundplaying")) {
             let removalDelay = Services.prefs.getIntPref("browser.tabs.delayHidingAudioPlayingIconMS");
+
+            tab.style.setProperty("--soundplaying-removal-delay", `${removalDelay - 300}ms`);
+            tab.setAttribute("soundplaying-scheduledremoval", "true");
+            this._tabAttrModified(tab, ["soundplaying-scheduledremoval"]);
+
             tab._soundPlayingAttrRemovalTimer = setTimeout(() => {
+              tab.removeAttribute("soundplaying-scheduledremoval");
               tab.removeAttribute("soundplaying");
-              this._tabAttrModified(tab, ["soundplaying"]);
+              this._tabAttrModified(tab, ["soundplaying", "soundplaying-scheduledremoval"]);
             }, removalDelay);
           }
         ]]>
       </handler>
     </handlers>
   </binding>
 
   <binding id="tabbrowser-tabbox"
@@ -5589,17 +5602,16 @@
 
           if (!("animLastScreenX" in draggedTab._dragData))
             draggedTab._dragData.animLastScreenX = draggedTab._dragData.screenX;
 
           let screenX = event.screenX;
           if (screenX == draggedTab._dragData.animLastScreenX)
             return;
 
-          let draggingRight = screenX > draggedTab._dragData.animLastScreenX;
           draggedTab._dragData.animLastScreenX = screenX;
 
           let rtl = (window.getComputedStyle(this).direction == "rtl");
           let pinned = draggedTab.pinned;
           let numPinned = this.tabbrowser._numPinnedTabs;
           let tabs = this.tabbrowser.visibleTabs
                                     .slice(pinned ? 0 : numPinned,
                                            pinned ? numPinned : undefined);
@@ -6539,25 +6551,25 @@
                      anonid="tab-icon-image"
                      class="tab-icon-image"
                      validate="never"
                      role="presentation"/>
           <xul:image xbl:inherits="sharing,selected=visuallyselected"
                      anonid="sharing-icon"
                      class="tab-sharing-icon-overlay"
                      role="presentation"/>
-          <xul:image xbl:inherits="crashed,busy,soundplaying,pinned,muted,selected=visuallyselected"
+          <xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,selected=visuallyselected"
                      anonid="overlay-icon"
                      class="tab-icon-overlay"
                      role="presentation"/>
           <xul:label flex="1"
                      xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected=visuallyselected,attention"
                      class="tab-text tab-label"
                      role="presentation"/>
-          <xul:image xbl:inherits="soundplaying,pinned,muted,selected=visuallyselected"
+          <xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,selected=visuallyselected"
                      anonid="soundplaying-icon"
                      class="tab-icon-sound"
                      role="presentation"/>
           <xul:toolbarbutton anonid="close-button"
                              xbl:inherits="fadein,pinned,selected=visuallyselected"
                              class="tab-close-button close-icon"/>
         </xul:hbox>
       </xul:stack>
@@ -7154,18 +7166,16 @@
         </getter>
 
         <setter>
         <![CDATA[
           if (val < 0 || val >= this.childNodes.length)
             return val;
 
           let toTab = this.getRelatedElement(this.childNodes[val]);
-          let fromTab = this._selectedPanel ? this.getRelatedElement(this._selectedPanel)
-                                            : null;
 
           gBrowser._getSwitcher().requestTab(toTab);
 
           var panel = this._selectedPanel;
           var newPanel = this.childNodes[val];
           this._selectedPanel = newPanel;
           if (this._selectedPanel != panel) {
             var event = document.createEvent("Events");
--- a/browser/base/content/test/alerts/browser_notification_close.js
+++ b/browser/base/content/test/alerts/browser_notification_close.js
@@ -1,14 +1,13 @@
 "use strict";
 
 const {PlacesTestUtils} =
   Cu.import("resource://testing-common/PlacesTestUtils.jsm", {});
 
-let tab;
 let notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
 let oldShowFavicons;
 
 add_task(function* test_notificationClose() {
   let pm = Services.perms;
   let notificationURI = makeURI(notificationURL);
   pm.add(notificationURI, "desktop-notification", pm.ALLOW_ACTION);
 
@@ -48,17 +47,17 @@ add_task(function* test_notificationClos
 
     let alertCloseButton = alertWindow.document.querySelector(".alertCloseButton");
     is(alertCloseButton.localName, "toolbarbutton", "close button found");
     let promiseBeforeUnloadEvent =
       BrowserTestUtils.waitForEvent(alertWindow, "beforeunload");
     let closedTime = alertWindow.Date.now();
     alertCloseButton.click();
     info("Clicked on close button");
-    let beforeUnloadEvent = yield promiseBeforeUnloadEvent;
+    yield promiseBeforeUnloadEvent;
 
     ok(true, "Alert should close when the close button is clicked");
     let currentTime = alertWindow.Date.now();
     // The notification will self-close at 12 seconds, so this checks
     // that the notification closed before the timeout.
     ok(currentTime - closedTime < 5000,
        "Close requested at " + closedTime + ", actually closed at " + currentTime);
   });
--- a/browser/base/content/test/general/browser_aboutAccounts.js
+++ b/browser/base/content/test/general/browser_aboutAccounts.js
@@ -124,17 +124,17 @@ var gTests = [
 },
 {
   desc: "Test action=signin - captive portal",
   teardown: () => gBrowser.removeCurrentTab(),
   run: function* ()
   {
     const signinUrl = "https://redirproxy.example.com/test";
     setPref("identity.fxaccounts.remote.signin.uri", signinUrl);
-    let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin");
+    let [tab, ] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin");
     yield checkVisibilities(tab, {
       stage: true, // parent of 'manage' and 'intro'
       manage: false,
       intro: false, // this is  "get started"
       remote: false,
       networkError: true
     });
   }
@@ -147,17 +147,17 @@ var gTests = [
   },
   run: function* ()
   {
     BrowserOffline.toggleOfflineStatus();
     Services.cache2.clear();
 
     const signinUrl = "https://unknowndomain.cow";
     setPref("identity.fxaccounts.remote.signin.uri", signinUrl);
-    let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin");
+    let [tab, ] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin");
     yield checkVisibilities(tab, {
       stage: true, // parent of 'manage' and 'intro'
       manage: false,
       intro: false, // this is  "get started"
       remote: false,
       networkError: true
     });
   }
@@ -206,28 +206,19 @@ var gTests = [
   teardown: function* () {
     gBrowser.removeCurrentTab();
     yield signOut();
   },
   run: function* ()
   {
     const expected_url = "https://example.com/?is_force_auth";
     setPref("identity.fxaccounts.remote.force_auth.uri", expected_url);
-    let userData = {
-      email: "foo@example.com",
-      uid: "1234@lcip.org",
-      assertion: "foobar",
-      sessionToken: "dead",
-      kA: "beef",
-      kB: "cafe",
-      verified: true
-    };
 
     yield setSignedInUser();
-    let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=reauth");
+    let [, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=reauth");
     // The current user will be appended to the url
     let expected = expected_url + "&email=foo%40example.com";
     is(url, expected, "action=reauth got the expected URL");
   },
 },
 {
   desc: "Test with migrateToDevEdition enabled (success)",
   teardown: function* () {
@@ -346,69 +337,69 @@ var gTests = [
   }
 },
 {
   desc: "Test entrypoint query string, no action, no user logged in",
   teardown: () => gBrowser.removeCurrentTab(),
   run: function* () {
     // When this loads with no user logged-in, we expect the "normal" URL
     setPref("identity.fxaccounts.remote.signup.uri", "https://example.com/");
-    let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?entrypoint=abouthome");
+    let [, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?entrypoint=abouthome");
     is(url, "https://example.com/?entrypoint=abouthome", "entrypoint=abouthome got the expected URL");
   },
 },
 {
   desc: "Test entrypoint query string for signin",
   teardown: () => gBrowser.removeCurrentTab(),
   run: function* () {
     // When this loads with no user logged-in, we expect the "normal" URL
     const expected_url = "https://example.com/?is_sign_in";
     setPref("identity.fxaccounts.remote.signin.uri", expected_url);
-    let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin&entrypoint=abouthome");
+    let [, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin&entrypoint=abouthome");
     is(url, expected_url + "&entrypoint=abouthome", "entrypoint=abouthome got the expected URL");
   },
 },
 {
   desc: "Test entrypoint query string for signup",
   teardown: () => gBrowser.removeCurrentTab(),
   run: function* () {
     // When this loads with no user logged-in, we expect the "normal" URL
     const sign_up_url = "https://example.com/?is_sign_up";
     setPref("identity.fxaccounts.remote.signup.uri", sign_up_url);
-    let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?entrypoint=abouthome&action=signup");
+    let [, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?entrypoint=abouthome&action=signup");
     is(url, sign_up_url + "&entrypoint=abouthome", "entrypoint=abouthome got the expected URL");
   },
 },
 {
   desc: "about:accounts URL params should be copied to remote URL params " +
         "when remote URL has no URL params, except for 'action'",
   teardown() {
     gBrowser.removeCurrentTab();
   },
   run: function* () {
     let signupURL = "https://example.com/";
     setPref("identity.fxaccounts.remote.signup.uri", signupURL);
     let queryStr = "email=foo%40example.com&foo=bar&baz=quux";
-    let [tab, url] =
+    let [, url] =
       yield promiseNewTabWithIframeLoadEvent("about:accounts?" + queryStr +
                                              "&action=action");
     is(url, signupURL + "?" + queryStr, "URL params are copied to signup URL");
   },
 },
 {
   desc: "about:accounts URL params should be copied to remote URL params " +
         "when remote URL already has some URL params, except for 'action'",
   teardown() {
     gBrowser.removeCurrentTab();
   },
   run: function* () {
     let signupURL = "https://example.com/?param";
     setPref("identity.fxaccounts.remote.signup.uri", signupURL);
     let queryStr = "email=foo%40example.com&foo=bar&baz=quux";
-    let [tab, url] =
+    let [, url] =
       yield promiseNewTabWithIframeLoadEvent("about:accounts?" + queryStr +
                                              "&action=action");
     is(url, signupURL + "&" + queryStr, "URL params are copied to signup URL");
   },
 },
 ]; // gTests
 
 function test()
--- a/browser/base/content/test/general/browser_aboutCertError.js
+++ b/browser/base/content/test/general/browser_aboutCertError.js
@@ -82,17 +82,17 @@ add_task(function* checkReturnToPrevious
   is(browser.webNavigation.canGoForward, true, "webNavigation.canGoForward");
   is(gBrowser.currentURI.spec, GOOD_PAGE, "Went back");
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkBadStsCert() {
   info("Loading a badStsCert and making sure exception button doesn't show up");
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
   let browser = gBrowser.selectedBrowser;
 
   info("Loading and waiting for the cert error");
   let certErrorLoaded = waitForCertErrorLoad(browser);
   BrowserTestUtils.loadURI(browser, BAD_STS_CERT);
   yield certErrorLoaded;
 
   let exceptionButtonHidden = yield ContentTask.spawn(browser, null, function* () {
@@ -106,17 +106,17 @@ add_task(function* checkBadStsCert() {
 });
 
 const PREF_BLOCKLIST_CLOCK_SKEW_SECONDS = "services.blocklist.clock_skew_seconds";
 
 add_task(function* checkWrongSystemTimeWarning() {
   function* setUpPage() {
     let browser;
     let certErrorLoaded;
-    let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+    yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
       gBrowser.selectedTab = gBrowser.addTab(BAD_CERT);
       browser = gBrowser.selectedBrowser;
       certErrorLoaded = waitForCertErrorLoad(browser);
     }, false);
 
     info("Loading and waiting for the cert error");
     yield certErrorLoaded;
 
@@ -206,17 +206,17 @@ add_task(function* checkWrongSystemTimeW
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkAdvancedDetails() {
   info("Loading a bad cert page and verifying the advanced details section");
   let browser;
   let certErrorLoaded;
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
     gBrowser.selectedTab = gBrowser.addTab(BAD_CERT);
     browser = gBrowser.selectedBrowser;
     certErrorLoaded = waitForCertErrorLoad(browser);
   }, false);
 
   info("Loading and waiting for the cert error");
   yield certErrorLoaded;
 
@@ -233,19 +233,16 @@ add_task(function* checkAdvancedDetails(
 
   message = yield ContentTask.spawn(browser, null, function* () {
     let doc = content.document;
     let errorCode = doc.getElementById("errorCode");
     errorCode.click();
     let div = doc.getElementById("certificateErrorDebugInformation");
     let text = doc.getElementById("certificateErrorText");
 
-    let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIWebNavigation)
-                          .QueryInterface(Ci.nsIDocShell);
     let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                      .getService(Ci.nsISerializationHelper);
     let serializable =  docShell.failedChannel.securityInfo
                                 .QueryInterface(Ci.nsITransportSecurityInfo)
                                 .QueryInterface(Ci.nsISerializable);
     let serializedSecurityInfo = serhelper.serializeToString(serializable);
     return {
       divDisplay: content.getComputedStyle(div).display,
@@ -266,17 +263,17 @@ add_task(function* checkAdvancedDetails(
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkAdvancedDetailsForHSTS() {
   info("Loading a bad STS cert page and verifying the advanced details section");
   let browser;
   let certErrorLoaded;
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
     gBrowser.selectedTab = gBrowser.addTab(BAD_STS_CERT);
     browser = gBrowser.selectedBrowser;
     certErrorLoaded = waitForCertErrorLoad(browser);
   }, false);
 
   info("Loading and waiting for the cert error");
   yield certErrorLoaded;
 
@@ -305,19 +302,16 @@ add_task(function* checkAdvancedDetailsF
 
   message = yield ContentTask.spawn(browser, null, function* () {
     let doc = content.document;
     let errorCode = doc.getElementById("errorCode");
     errorCode.click();
     let div = doc.getElementById("certificateErrorDebugInformation");
     let text = doc.getElementById("certificateErrorText");
 
-    let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIWebNavigation)
-                          .QueryInterface(Ci.nsIDocShell);
     let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                      .getService(Ci.nsISerializationHelper);
     let serializable =  docShell.failedChannel.securityInfo
                                 .QueryInterface(Ci.nsITransportSecurityInfo)
                                 .QueryInterface(Ci.nsISerializable);
     let serializedSecurityInfo = serhelper.serializeToString(serializable);
     return {
       divDisplay: content.getComputedStyle(div).display,
@@ -338,17 +332,17 @@ add_task(function* checkAdvancedDetailsF
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkUnknownIssuerLearnMoreLink() {
   info("Loading a cert error for self-signed pages and checking the correct link is shown");
   let browser;
   let certErrorLoaded;
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
     gBrowser.selectedTab = gBrowser.addTab(UNKNOWN_ISSUER);
     browser = gBrowser.selectedBrowser;
     certErrorLoaded = waitForCertErrorLoad(browser);
   }, false);
 
   info("Loading and waiting for the cert error");
   yield certErrorLoaded;
 
--- a/browser/base/content/test/general/browser_aboutNetError.js
+++ b/browser/base/content/test/general/browser_aboutNetError.js
@@ -10,17 +10,17 @@ Services.prefs.setIntPref("security.tls.
 const LOW_TLS_VERSION = "https://tls1.example.com/";
 const {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
 const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
 
 add_task(function* checkReturnToPreviousPage() {
   info("Loading a TLS page that isn't supported, ensure we have a fix button and clicking it then loads the page");
   let browser;
   let pageLoaded;
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
     gBrowser.selectedTab = gBrowser.addTab(LOW_TLS_VERSION);
     browser = gBrowser.selectedBrowser;
     pageLoaded = BrowserTestUtils.waitForErrorPage(browser);
   }, false);
 
   info("Loading and waiting for the net error");
   yield pageLoaded;
 
@@ -34,9 +34,8 @@ add_task(function* checkReturnToPrevious
     content.document.getElementById("prefResetButton").click();
   });
   yield pageshowPromise;
 
   Assert.equal(content.document.documentURI, LOW_TLS_VERSION, "Should not be showing page");
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
-
--- a/browser/base/content/test/general/browser_aboutTabCrashed_showForm.js
+++ b/browser/base/content/test/general/browser_aboutTabCrashed_showForm.js
@@ -11,18 +11,16 @@ requestLongerTimeout(2);
  * Tests that we show the about:tabcrashed additional details form
  * if the "submit a crash report" checkbox was checked by default.
  */
 add_task(function* test_show_form() {
   return BrowserTestUtils.withNewTab({
     gBrowser,
     url: PAGE,
   }, function*(browser) {
-    let tab = gBrowser.getTabForBrowser(browser);
-
     // Flip the pref so that the checkbox should be checked
     // by default.
     let pref = TabCrashHandler.prefs.root + "sendReport";
     yield pushPrefs([pref, true]);
 
     // Now crash the browser.
     yield BrowserTestUtils.crashBrowser(browser);
 
--- a/browser/base/content/test/general/browser_bug409624.js
+++ b/browser/base/content/test/general/browser_bug409624.js
@@ -21,19 +21,16 @@ add_task(function* test() {
                            }
                          },
                        });
   });
 
   let prefService = Cc["@mozilla.org/preferences-service;1"]
                     .getService(Components.interfaces.nsIPrefService);
 
-  let findBar = gFindBar;
-  let textbox = gFindBar.getElement("findbar-textbox");
-
   let tempScope = {};
   Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
                                              .loadSubScript("chrome://browser/content/sanitize.js", tempScope);
   let Sanitizer = tempScope.Sanitizer;
   let s = new Sanitizer();
   s.prefDomain = "privacy.cpd.";
   let prefBranch = prefService.getBranch(s.prefDomain);
 
--- a/browser/base/content/test/general/browser_bug431826.js
+++ b/browser/base/content/test/general/browser_bug431826.js
@@ -14,18 +14,16 @@ add_task(function* () {
   yield promise;
 
   yield remote(() => {
     // Confirm that we are displaying the contributed error page, not the default
     let uri = content.document.documentURI;
     Assert.ok(uri.startsWith("about:certerror"), "Broken page should go to about:certerror, not about:neterror");
   });
 
-  let advancedDiv, advancedDivVisibility, technicalDivCollapsed;
-
   yield remote(() => {
     let div = content.document.getElementById("badCertAdvancedPanel");
     // Confirm that the expert section is collapsed
     Assert.ok(div, "Advanced content div should exist");
     Assert.equal(div.ownerGlobal.getComputedStyle(div).display,
       "none", "Advanced content should not be visible by default");
   });
 
--- a/browser/base/content/test/general/browser_bug460146.js
+++ b/browser/base/content/test/general/browser_bug460146.js
@@ -3,17 +3,16 @@
 function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
 
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
-    var doc = gBrowser.contentDocument;
     var pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
                                    "mediaTab");
 
     pageInfo.addEventListener("load", function () {
       pageInfo.removeEventListener("load", arguments.callee, true);
       pageInfo.onFinished.push(function () {
         executeSoon(function () {
           var imageTree = pageInfo.document.getElementById("imagetree");
--- a/browser/base/content/test/general/browser_bug553455.js
+++ b/browser/base/content/test/general/browser_bug553455.js
@@ -1020,24 +1020,16 @@ function test_renotifyInstalled() {
 
     Services.perms.remove(makeURI("http://example.com/"), "install");
     yield removeTab();
   });
 },
 
 function test_cancel() {
   return Task.spawn(function* () {
-    function complete_install(callback) {
-      let url = TESTROOT + "slowinstall.sjs?continue=true"
-      NetUtil.asyncFetch({
-        uri: url,
-        loadUsingSystemPrincipal: true
-      }, callback || (() => {}));
-    }
-
     let pm = Services.perms;
     pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
     let notificationPromise = waitForNotification(PROGRESS_NOTIFICATION);
     let triggers = encodeURIComponent(JSON.stringify({
       "XPI": "slowinstall.sjs?file=amosigned.xpi"
     }));
     BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
--- a/browser/base/content/test/general/browser_bug585830.js
+++ b/browser/base/content/test/general/browser_bug585830.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 function test() {
   let tab1 = gBrowser.selectedTab;
   let tab2 = gBrowser.addTab("about:blank", {skipAnimation: true});
-  let tab3 = gBrowser.addTab();
+  gBrowser.addTab();
   gBrowser.selectedTab = tab2;
 
   gBrowser.removeCurrentTab({animate: true});
   gBrowser.tabContainer.advanceSelectedTab(-1, true);
   is(gBrowser.selectedTab, tab1, "First tab should be selected");
   gBrowser.removeTab(tab2);
 
   // test for "null has no properties" fix. See Bug 585830 Comment 13
--- a/browser/base/content/test/general/browser_bug592338.js
+++ b/browser/base/content/test/general/browser_bug592338.js
@@ -52,20 +52,19 @@ function test_install_lwtheme() {
   gBrowser.selectedTab = gBrowser.addTab("https://example.com/browser/browser/base/content/test/general/bug592338.html");
   gBrowser.selectedBrowser.addEventListener("pageshow", function() {
     if (gBrowser.contentDocument.location.href == "about:blank")
       return;
 
     gBrowser.selectedBrowser.removeEventListener("pageshow", arguments.callee, false);
 
     BrowserTestUtils.synthesizeMouse("#theme-install", 2, 2, {}, gBrowser.selectedBrowser);
-    let notification;
     let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
     waitForCondition(
-      () => (notification = notificationBox.getNotificationWithValue("lwtheme-install-notification")),
+      () => notificationBox.getNotificationWithValue("lwtheme-install-notification"),
       () => {
         is(LightweightThemeManager.currentTheme.id, "test", "Should have installed the test theme");
 
         LightweightThemeManager.currentTheme = null;
         gBrowser.removeTab(gBrowser.selectedTab);
         Services.perms.remove(makeURI("http://example.com/"), "install");
 
         runNextTest();
--- a/browser/base/content/test/general/browser_bug676619.js
+++ b/browser/base/content/test/general/browser_bug676619.js
@@ -1,18 +1,18 @@
 function test () {
   requestLongerTimeout(3);
   waitForExplicitFinish();
 
   var isHTTPS = false;
 
   function loadListener() {
     function testLocation(link, url, next) {
-      var tabOpenListener = new TabOpenListener(url, function () {
-          gBrowser.removeTab(this.tab);
+      new TabOpenListener(url, function () {
+        gBrowser.removeTab(this.tab);
       }, function () {
         next();
       });
 
       ContentTask.spawn(gBrowser.selectedBrowser, link, link => {
         content.document.getElementById(link).click();
       });
     }
--- a/browser/base/content/test/general/browser_bug678392.js
+++ b/browser/base/content/test/general/browser_bug678392.js
@@ -152,17 +152,16 @@ function test1() {
   });
 }
 
 function test2() {
   // Test growing of snapshot array across tabs.
   let tab = gBrowser.selectedTab;
 
   load(tab, HTTPROOT + "browser_bug678392-1.html", function() {
-    var historyIndex = gBrowser.webNavigation.sessionHistory.index - 1;
     load(tab, HTTPROOT + "browser_bug678392-2.html", function() {
       is(gHistorySwipeAnimation._trackedSnapshots.length, 2, "Length of " +
          "snapshot array is equal to 2 after loading two pages");
       let prevTab = tab;
       tab = gBrowser.addTab("about:newtab");
       gBrowser.selectedTab = tab;
       load(tab, HTTPROOT + "browser_bug678392-2.html" /* initial page */,
            function() {
--- a/browser/base/content/test/general/browser_bug822367.js
+++ b/browser/base/content/test/general/browser_bug822367.js
@@ -120,17 +120,16 @@ function MixedTest4A() {
 function MixedTest4B() {
   waitForCondition(() => content.document.location == gHttpTestRoot + "file_bug822367_4B.html", MixedTest4C, "Waited too long for mixed script to run in Test 4");
 }
 function MixedTest4C() {
   ok(content.document.location == gHttpTestRoot + "file_bug822367_4B.html", "Location didn't change in test 4");
 
   assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
   waitForCondition(() => content.document.getElementById('p1').innerHTML == "", MixedTest4D, "Mixed script loaded in test 4 after location change!");
 }
 function MixedTest4D() {
   ok(content.document.getElementById('p1').innerHTML == "", "p1.innerHTML changed; mixed script loaded after location change in Test 4");
   MixedTest5();
 }
 
 // Mixed script attempts to load in a document.open()
--- a/browser/base/content/test/general/browser_contentSearchUI.js
+++ b/browser/base/content/test/general/browser_contentSearchUI.js
@@ -577,17 +577,16 @@ add_task(function* search() {
                           { str: "xfoo", type: "formHistory" }, "xbar"], 0);
 
   // Mouse over the second suggestion.
   state = yield msg("mousemove", 1);
   checkState(state, "x", [{ str: "x", type: "formHistory" },
                           { str: "xfoo", type: "formHistory" }, "xbar"], 1);
 
   modifiers.button = 0;
-  let currentTab = gBrowser.selectedTab;
   p = msg("waitForSearch");
   yield msg("click", { eltIdx: 1, modifiers: modifiers });
   mesg = yield p;
   eventData.searchString = "xfoo";
   eventData.originalEvent = modifiers;
   eventData.selection = {
     index: 1,
     kind: "mouse",
@@ -755,17 +754,17 @@ function promiseMsg(name, type, msgMan) 
 
 function setUpEngines() {
   return Task.spawn(function* () {
     info("Removing default search engines");
     let currentEngineName = Services.search.currentEngine.name;
     let currentEngines = Services.search.getVisibleEngines();
     info("Adding test search engines");
     let engine1 = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
-    let engine2 = yield promiseNewSearchEngine(TEST_ENGINE_2_BASENAME);
+    yield promiseNewSearchEngine(TEST_ENGINE_2_BASENAME);
     Services.search.currentEngine = engine1;
     for (let engine of currentEngines) {
       Services.search.removeEngine(engine);
     }
     registerCleanupFunction(() => {
       Services.search.restoreDefaultEngines();
       Services.search.currentEngine = Services.search.getEngineByName(currentEngineName);
     });
--- a/browser/base/content/test/general/browser_contextmenu_childprocess.js
+++ b/browser/base/content/test/general/browser_contextmenu_childprocess.js
@@ -7,17 +7,17 @@ add_task(function *() {
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gBaseURL + "subtst_contextmenu.html");
 
   let contextMenu = document.getElementById("contentAreaContextMenu");
 
   // Get the point of the element with the page menu (test-pagemenu) and
   // synthesize a right mouse click there.
   let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
   yield BrowserTestUtils.synthesizeMouse("#test-pagemenu", 5, 5, { type : "contextmenu", button : 2 }, tab.linkedBrowser);
-  let event = yield popupShownPromise;
+  yield popupShownPromise;
 
   checkMenu(contextMenu);
 
   let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
   contextMenu.hidePopup();
   yield popupHiddenPromise;
 
   yield BrowserTestUtils.removeTab(tab);
--- a/browser/base/content/test/general/browser_datachoices_notification.js
+++ b/browser/base/content/test/general/browser_datachoices_notification.js
@@ -87,17 +87,17 @@ var checkInfobarButton = Task.async(func
   // Add an observer to ensure the "advanced" pane opened (but don't bother
   // closing it - we close the entire window when done.)
   let paneLoadedPromise = promiseTopicObserved("advanced-pane-loaded");
 
   // Click on the button.
   button.click();
 
   // Wait for the preferences panel to open.
-  let preferenceWindow = yield paneLoadedPromise;
+  yield paneLoadedPromise;
   yield promiseNextTick();
 });
 
 add_task(function* setup() {
   const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, true);
   const currentPolicyVersion = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1);
 
   // Register a cleanup function to reset our preferences.
--- a/browser/base/content/test/general/browser_double_close_tab.js
+++ b/browser/base/content/test/general/browser_double_close_tab.js
@@ -39,17 +39,17 @@ function waitForDialogDestroyed(node, ca
 add_task(function*() {
   testTab = gBrowser.selectedTab = gBrowser.addTab();
   yield promiseTabLoadEvent(testTab, TEST_PAGE);
   // XXXgijs the reason this has nesting and callbacks rather than promises is
   // that DOM promises resolve on the next tick. So they're scheduled
   // in an event queue. So when we spin a new event queue for a modal dialog...
   // everything gets messed up and the promise's .then callbacks never get
   // called, despite resolve() being called just fine.
-  let dialogNode = yield new Promise(resolveOuter => {
+  yield new Promise(resolveOuter => {
     waitForDialog(dialogNode => {
       waitForDialogDestroyed(dialogNode, () => {
         let doCompletion = () => setTimeout(resolveOuter, 0);
         info("Now checking if dialog is destroyed");
         ok(!dialogNode.parentNode, "onbeforeunload dialog should be gone.");
         if (dialogNode.parentNode) {
           // Failed to remove onbeforeunload dialog, so do it ourselves:
           let leaveBtn = dialogNode.ui.button0;
@@ -73,10 +73,8 @@ registerCleanupFunction(function() {
   if (testTab.parentNode) {
     // Remove the handler, or closing this tab will prove tricky:
     try {
       testTab.linkedBrowser.contentWindow.onbeforeunload = null;
     } catch (ex) {}
     gBrowser.removeTab(testTab);
   }
 });
-
-
--- a/browser/base/content/test/general/browser_fullscreen-window-open.js
+++ b/browser/base/content/test/general/browser_fullscreen-window-open.js
@@ -177,17 +177,16 @@ function test_open_from_chrome() {
       title: "test_open_from_chrome",
       param: "",
     },
     finalizeFn: function () {}
   });
 }
 
 function waitForTabOpen(aOptions) {
-  let start = Date.now();
   let message = aOptions.message;
 
   if (!message.title) {
     ok(false, "Can't get message.title.");
     aOptions.finalizeFn();
     runNextTest();
     return;
   }
@@ -226,17 +225,16 @@ function waitForTabOpen(aOptions) {
     uri: URI,
     title: message.title,
     option: message.param,
   });
 }
 
 
 function waitForWindowOpen(aOptions) {
-  let start = Date.now();
   let message = aOptions.message;
   let url = aOptions.url || "about:blank";
 
   if (!message.title) {
     ok(false, "Can't get message.title");
     aOptions.finalizeFn();
     runNextTest();
     return;
@@ -268,17 +266,16 @@ function executeWindowOpenInContent(aPar
   ContentTask.spawn(gBrowser.selectedBrowser, JSON.stringify(aParam), function* (dataTestParam) {
     let testElm = content.document.getElementById("test");
     testElm.setAttribute("data-test-param", dataTestParam);
     testElm.click();
   });
 }
 
 function waitForWindowOpenFromChrome(aOptions) {
-  let start = Date.now();
   let message = aOptions.message;
   let url = aOptions.url || "about:blank";
 
   if (!message.title) {
     ok(false, "Can't get message.title");
     aOptions.finalizeFn();
     runNextTest();
     return;
@@ -294,17 +291,17 @@ function waitForWindowOpenFromChrome(aOp
   };
 
   let listener = new WindowListener(message.title, getBrowserURL(), {
     onSuccess: aOptions.successFn,
     onFinalize: onFinalize,
   });
   Services.wm.addListener(listener);
 
-  let testWindow = window.open(url, message.title, message.option);
+  window.open(url, message.title, message.option);
 }
 
 function WindowListener(aTitle, aUrl, aCallBackObj) {
   this.test_title = aTitle;
   this.test_url = aUrl;
   this.callback_onSuccess = aCallBackObj.onSuccess;
   this.callBack_onFinalize = aCallBackObj.onFinalize;
 }
--- a/browser/base/content/test/general/browser_gestureSupport.js
+++ b/browser/base/content/test/general/browser_gestureSupport.js
@@ -541,17 +541,16 @@ function test_rotateHelperGetImageRotati
 function test_rotateHelperOneGesture(aImageElement, aCurrentRotation,
                                      aDirection, aAmount, aStop)
 {
   if (aAmount <= 0 || aAmount > 90) // Bound to 0 < aAmount <= 90
     return;
 
   // easier to type names for the direction constants
   let clockwise = SimpleGestureEvent.ROTATION_CLOCKWISE;
-  let cclockwise = SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE;
 
   let delta = aAmount * (aDirection == clockwise ? 1 : -1);
 
   // Kill transition time on image so test isn't wrong and doesn't take 10 seconds
   aImageElement.style.transitionDuration = "0s";
 
   // Start the gesture, perform an update, and force flush
   test_utils.sendSimpleGestureEvent("MozRotateGestureStart", 0, 0, aDirection, .001, 0);
--- a/browser/base/content/test/general/browser_page_style_menu_update.js
+++ b/browser/base/content/test/general/browser_page_style_menu_update.js
@@ -40,17 +40,16 @@ add_task(function*() {
   gPageStyleMenu.fillPopup(menupopup);
 
   // page_style_sample.html should default us to selecting the stylesheet
   // with the title "6" first.
   let selected = menupopup.querySelector("menuitem[checked='true']");
   is(selected.getAttribute("label"), "6", "Should have '6' stylesheet selected by default");
 
   // Now select stylesheet "1"
-  let targets = menupopup.querySelectorAll("menuitem");
   let target = menupopup.querySelector("menuitem[label='1']");
   target.click();
 
   // Now we need to wait for the content process to send its stylesheet
   // update for the selected tab to the parent. Because messages are
   // guaranteed to be sent in order, we'll make sure we do the check
   // after the parent has been updated by yielding until the child
   // has finished running a ContentTask for us.
--- a/browser/base/content/test/general/browser_parsable_script.js
+++ b/browser/base/content/test/general/browser_parsable_script.js
@@ -43,20 +43,19 @@ function uriIsWhiteListed(uri) {
 
 function parsePromise(uri) {
   let promise = new Promise((resolve, reject) => {
     let xhr = new XMLHttpRequest();
     xhr.open("GET", uri, true);
     xhr.onreadystatechange = function() {
       if (this.readyState == this.DONE) {
         let scriptText = this.responseText;
-        let ast;
         try {
           info("Checking " + uri);
-          ast = Reflect.parse(scriptText);
+          Reflect.parse(scriptText);
           resolve(true);
         } catch (ex) {
           let errorMsg = "Script error reading " + uri + ": " + ex;
           ok(false, errorMsg);
           resolve(false);
         }
       }
     };
@@ -126,9 +125,8 @@ add_task(function* checkAllTheJS() {
       continue;
     }
     allPromises.push(parsePromise(uri.spec));
   }
 
   let promiseResults = yield Promise.all(allPromises);
   is(promiseResults.filter((x) => !x).length, 0, "There should be 0 parsing errors");
 });
-
--- a/browser/base/content/test/general/browser_permissions.js
+++ b/browser/base/content/test/general/browser_permissions.js
@@ -27,17 +27,16 @@ function* openIdentityPopup() {
 function* closeIdentityPopup() {
   let {gIdentityHandler} = gBrowser.ownerGlobal;
   let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
   gIdentityHandler._identityPopup.hidePopup();
   return promise;
 }
 
 add_task(function* testMainViewVisible() {
-  let {gIdentityHandler} = gBrowser.ownerGlobal;
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   yield promiseTabLoadEvent(tab, PERMISSIONS_PAGE);
 
   let permissionsList = document.getElementById("identity-popup-permission-list");
   let emptyLabel = permissionsList.nextSibling.nextSibling;
 
   yield openIdentityPopup();
 
@@ -97,17 +96,16 @@ add_task(function* testIdentityIcon() {
     "identity-box signals granted permissions");
 
   SitePermissions.remove(gBrowser.currentURI, "geo");
   SitePermissions.remove(gBrowser.currentURI, "camera");
   SitePermissions.remove(gBrowser.currentURI, "cookie");
 });
 
 add_task(function* testCancelPermission() {
-  let {gIdentityHandler} = gBrowser.ownerGlobal;
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   yield promiseTabLoadEvent(tab, PERMISSIONS_PAGE);
 
   let permissionsList = document.getElementById("identity-popup-permission-list");
   let emptyLabel = permissionsList.nextSibling.nextSibling;
 
   SitePermissions.set(gBrowser.currentURI, "geo", SitePermissions.ALLOW);
   SitePermissions.set(gBrowser.currentURI, "camera", SitePermissions.BLOCK);
@@ -125,17 +123,16 @@ add_task(function* testCancelPermission(
   cancelButtons[1].click();
   labels = permissionsList.querySelectorAll(".identity-popup-permission-label");
   is(labels.length, 0, "One permission should be removed");
 
   yield closeIdentityPopup();
 });
 
 add_task(function* testPermissionHints() {
-  let {gIdentityHandler} = gBrowser.ownerGlobal;
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   yield promiseTabLoadEvent(tab, PERMISSIONS_PAGE);
 
   let permissionsList = document.getElementById("identity-popup-permission-list");
   let emptyHint = document.getElementById("identity-popup-permission-empty-hint");
   let reloadHint = document.getElementById("identity-popup-permission-reload-hint");
 
   yield openIdentityPopup();
--- a/browser/base/content/test/general/browser_purgehistory_clears_sh.js
+++ b/browser/base/content/test/general/browser_purgehistory_clears_sh.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const url = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
 
 add_task(function* purgeHistoryTest() {
-  let tab = yield BrowserTestUtils.withNewTab({
+  yield BrowserTestUtils.withNewTab({
     gBrowser,
     url,
   }, function* purgeHistoryTestInner(browser) {
     let backButton = browser.ownerDocument.getElementById("Browser:Back");
     let forwardButton = browser.ownerDocument.getElementById("Browser:Forward");
 
     ok(!browser.webNavigation.canGoBack,
        "Initial value for webNavigation.canGoBack");
--- a/browser/base/content/test/general/browser_readerMode.js
+++ b/browser/base/content/test/general/browser_readerMode.js
@@ -108,21 +108,19 @@ add_task(function* test_getOriginalUrl()
 add_task(function* test_reader_view_element_attribute_transform() {
   registerCleanupFunction(function() {
     while (gBrowser.tabs.length > 1) {
       gBrowser.removeCurrentTab();
     }
   });
 
   function observeAttribute(element, attribute, triggerFn, checkFn) {
-    let initValue = element.getAttribute(attribute);
     return new Promise(resolve => {
       let observer = new MutationObserver((mutations) => {
         mutations.forEach( mu => {
-          let muValue = element.getAttribute(attribute);
           if (element.getAttribute(attribute) !== mu.oldValue) {
             checkFn();
             resolve();
             observer.disconnect();
           }
         });
       });
 
--- a/browser/base/content/test/general/browser_relatedTabs.js
+++ b/browser/base/content/test/general/browser_relatedTabs.js
@@ -5,17 +5,16 @@
 add_task(function*() {
   is(gBrowser.tabs.length, 1, "one tab is open initially");
 
   // Add several new tabs in sequence, interrupted by selecting a
   // different tab, moving a tab around and closing a tab,
   // returning a list of opened tabs for verifying the expected order.
   // The new tab behaviour is documented in bug 465673
   let tabs = [];
-  let promises = [];
   function addTab(aURL, aReferrer) {
     let tab = gBrowser.addTab(aURL, {referrerURI: aReferrer});
     tabs.push(tab);
     return BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   }
 
   yield addTab("http://mochi.test:8888/#0");
   gBrowser.selectedTab = tabs[0];
--- a/browser/base/content/test/general/browser_removeTabsToTheEnd.js
+++ b/browser/base/content/test/general/browser_removeTabsToTheEnd.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 function test() {
   // Add two new tabs after the original tab. Pin the first one.
   let originalTab = gBrowser.selectedTab;
   let newTab1 = gBrowser.addTab();
-  let newTab2 = gBrowser.addTab();
+  gBrowser.addTab();
   gBrowser.pinTab(newTab1);
 
   // Check that there is only one closable tab from originalTab to the end
   is(gBrowser.getTabsToTheEndFrom(originalTab).length, 1,
     "One unpinned tab to the right");
 
   // Remove tabs to the end
   gBrowser.removeTabsToTheEndFrom(originalTab);
--- a/browser/base/content/test/general/browser_sanitizeDialog.js
+++ b/browser/base/content/test/general/browser_sanitizeDialog.js
@@ -131,17 +131,16 @@ add_task(function* test_history_download
   for (let i = 0; i < 5; i++) {
     pURI = makeURI("http://" + (61 + i) + "-minutes-ago.com/");
     places.push({uri: pURI, visitDate: visitTimeForMinutesAgo(61 + i)});
     olderURIs.push(pURI);
   }
   let promiseSanitized = promiseSanitizationComplete();
 
   yield PlacesTestUtils.addVisits(places);
-  let totalHistoryVisits = uris.length + olderURIs.length;
 
   let wh = new WindowHelper();
   wh.onload = function () {
     this.selectDuration(Sanitizer.TIMESPAN_HOUR);
     this.checkPrefCheckbox("history", true);
     this.acceptDialog();
   };
   wh.onunload = function* () {
--- a/browser/base/content/test/general/browser_save_video_frame.js
+++ b/browser/base/content/test/general/browser_save_video_frame.js
@@ -99,17 +99,16 @@ add_task(function*() {
 
   let tab = gBrowser.addTab();
   gBrowser.selectedTab = tab;
   let browser = tab.linkedBrowser;
   info("Loading video tab");
   yield promiseTabLoadEvent(tab, VIDEO_URL);
   info("Video tab loaded.");
 
-  let video = browser.contentDocument.getElementById("video1");
   let context = document.getElementById("contentAreaContextMenu");
   let popupPromise = promisePopupShown(context);
 
   info("Synthesizing right-click on video element");
   rightClickVideo(browser);
   info("Waiting for popup to fire popupshown.");
   yield popupPromise;
   info("Popup fired popupshown");
--- a/browser/base/content/test/general/browser_tabDrop.js
+++ b/browser/base/content/test/general/browser_tabDrop.js
@@ -83,17 +83,16 @@ function* drop(dragData, expectedTabOpen
   var event = {
     clientX: 0,
     clientY: 0,
     screenX: 0,
     screenY: 0,
   };
   EventUtils.synthesizeDrop(gBrowser.selectedTab, gBrowser.selectedTab, dragData, "link", window, undefined, event);
   let tabsOpened = false;
-  let tabOpened = false;
   if (awaitTabOpen) {
     yield awaitTabOpen;
     info("Got TabOpen event");
     tabsOpened = true;
     for (let tab of openedTabs) {
       yield BrowserTestUtils.removeTab(tab);
     }
   }
--- a/browser/base/content/test/general/browser_tabfocus.js
+++ b/browser/base/content/test/general/browser_tabfocus.js
@@ -141,17 +141,16 @@ add_task(function*() {
 
   var childFocusScript = "data:,(" + focusInChild.toString() + ")();";
   browser1.messageManager.loadFrameScript(childFocusScript, true);
   browser2.messageManager.loadFrameScript(childFocusScript, true);
 
   gURLBar.focus();
   yield SimpleTest.promiseFocus();
 
-  var messages = "";
   if (gMultiProcessBrowser) {
     messageManager.addMessageListener("Browser:FocusChanged", message => {
       actualEvents.push(message.data.details);
       compareFocusResults();
     });
   }
 
   _lastfocus = "urlbar";
@@ -560,9 +559,8 @@ function* expectFocusShift(callback, exp
 
     // No events are expected, so resolve the promise immediately.
     if (expectedEvents["main-window"].length + expectedEvents["window1"].length + expectedEvents["window2"].length == 0) {
       currentPromiseResolver();
       currentPromiseResolver = null;
     }
   });
 }
-
--- a/browser/base/content/test/general/browser_tabkeynavigation.js
+++ b/browser/base/content/test/general/browser_tabkeynavigation.js
@@ -135,17 +135,16 @@ add_task(function* test() {
     gBrowser.selectedTab = tab2;
     EventUtils.synthesizeKey("VK_F4", { type: "keydown", ctrlKey: true });
 
     isnot(gBrowser.selectedTab, tab2,
           "Tab2 should be closed by pressing Ctrl+F4 on Tab2");
     is(gBrowser.tabs.length, 3,
       "The count of tabs should be 3 since tab2 should be closed");
 
-    let activeWindow = gBrowser.getBrowserForTab(gBrowser.selectedTab).contentWindow;
     // NOTE: keypress event shouldn't be fired since the keydown event should
     //       be consumed by tab2.
       EventUtils.synthesizeKey("VK_F4", { type: "keyup", ctrlKey: true });
       is(gBrowser.tabs.length, 3,
         "The count of tabs should be 3 since renaming key events shouldn't close other tabs");
   }
 
   gBrowser.selectedTab = tab3;
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -1052,17 +1052,17 @@ function getPropertyBagValue(bag, key) {
  *        in expectedExtra. It's possible that the crash report
  *        will contain other extra information that is not
  *        compared against.
  * @returns Promise
  */
 function promiseCrashReport(expectedExtra={}) {
   return Task.spawn(function*() {
     info("Starting wait on crash-report-status");
-    let [subject, data] =
+    let [subject, ] =
       yield TestUtils.topicObserved("crash-report-status", (subject, data) => {
         return data == "success";
       });
     info("Topic observed!");
 
     if (!(subject instanceof Ci.nsIPropertyBag2)) {
       throw new Error("Subject was not a Ci.nsIPropertyBag2");
     }
--- a/browser/base/content/test/newtab/browser_newtab_bug991111.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug991111.js
@@ -8,17 +8,16 @@ add_task(function* () {
   yield* addNewTabPageTab();
   // we need a second newtab to honor max rows
   yield* addNewTabPageTab();
 
   yield ContentTask.spawn(gBrowser.selectedBrowser, {index: 0}, function* (args) {
     let {site} = content.wrappedJSObject.gGrid.cells[args.index];
 
     let origOnClick = site.onClick;
-    let clicked = false;
     site.onClick = e => {
       origOnClick.call(site, e);
       sendAsyncMessage("test:clicked-on-cell", {});
     };
   });
 
   let mm = gBrowser.selectedBrowser.messageManager;
   let messagePromise = new Promise(resolve => {
--- a/browser/base/content/test/newtab/browser_newtab_bug991210.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug991210.js
@@ -10,17 +10,17 @@ add_task(function* () {
     getLinks: function(callback) {
       this.callback = callback;
     },
     addObserver: function() {},
   };
   NewTabUtils.links.addProvider(afterLoadProvider);
 
   // wait until about:newtab loads before calling provider callback
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab");
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab");
 
   afterLoadProvider.callback([]);
 
   yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
     let {_cellMargin, _cellHeight, _cellWidth, node} = content.gGrid;
     Assert.notEqual(_cellMargin, null, "grid has a computed cell margin");
     Assert.notEqual(_cellHeight, null, "grid has a computed cell height");
     Assert.notEqual(_cellWidth, null, "grid has a computed cell width");
--- a/browser/base/content/test/newtab/browser_newtab_bug998387.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug998387.js
@@ -8,17 +8,16 @@ add_task(function* () {
   yield* addNewTabPageTab();
   // we need a second newtab to honor max rows
   yield* addNewTabPageTab();
 
   yield ContentTask.spawn(gBrowser.selectedBrowser, {index: 0}, function* (args) {
     let {site} = content.wrappedJSObject.gGrid.cells[args.index];
 
     let origOnClick = site.onClick;
-    let clicked = false;
     site.onClick = e => {
       origOnClick.call(site, e);
       sendAsyncMessage("test:clicked-on-cell", {});
     };
   });
 
   let mm = gBrowser.selectedBrowser.messageManager;
   let messagePromise = new Promise(resolve => {
@@ -33,9 +32,8 @@ add_task(function* () {
                                                  {button: 1}, gBrowser.selectedBrowser);
 
   yield messagePromise;
   ok(true, "middle click triggered click listener");
 
   // Make sure the cell didn't actually get blocked
   yield* checkGrid("0");
 });
-
--- a/browser/base/content/test/newtab/browser_newtab_enhanced.js
+++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js
@@ -116,17 +116,16 @@ add_task(function* () {
   data = yield getData(1);
   is(data, null, "directory link still pushed out by pinned history link");
 
   yield unpinCell(0);
 
 
 
   // Test that a suggested tile is not enhanced by a directory tile
-  let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = () => true;
   yield setLinks("-1,2,3,4,5,6,7,8");
 
   // Test with enhanced = false
   yield* addNewTabPageTab();
   ({type, enhanced, title, suggested} = yield getData(0));
   isnot(type, "enhanced", "history link is not enhanced");
   is(enhanced, "", "history link has no enhanced image");
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -146,17 +146,17 @@ add_task(function* setup() {
   * @param aIndex index of cell
   * @param aFn function to call in child process or tab.
   * @returns result of calling the function.
   */
 function performOnCell(aIndex, aFn) {
   return ContentTask.spawn(gWindow.gBrowser.selectedBrowser,
                            { index: aIndex, fn: aFn.toString() }, function* (args) {
     let cell = content.gGrid.cells[args.index];
-    return eval("(" + args.fn + ")(cell)");
+    return eval(args.fn)(cell);
   });
 }
 
 /**
  * Allows to provide a list of links that is used to construct the grid.
  * @param aLinksPattern the pattern (see below)
  *
  * Example: setLinks("-1,0,1,2,3")
@@ -409,18 +409,16 @@ function* simulateExternalDrop(aDestInde
     return new Promise(resolve => {
       const url = "data:text/html;charset=utf-8," +
                   "<a id='link' href='http://example99.com/'>link</a>";
 
       let doc = content.document;
       let iframe = doc.createElement("iframe");
 
       function iframeLoaded() {
-        let link = iframe.contentDocument.getElementById("link");
-
         let dataTransfer = new iframe.contentWindow.DataTransfer("dragstart", false);
         dataTransfer.mozSetDataAt("text/x-moz-url", "http://example99.com/", 0);
 
         let event = content.document.createEvent("DragEvent");
         event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
                             false, false, false, false, 0, null, dataTransfer);
 
         let target = content.gGrid.cells[dropIndex].node;
--- a/browser/base/content/test/plugins/browser_CTP_crashreporting.js
+++ b/browser/base/content/test/plugins/browser_CTP_crashreporting.js
@@ -134,17 +134,17 @@ add_task(function*() {
 
       // And wait for the parent to say that the crash report was submitted
       // successfully.
       yield ContentTaskUtils.waitForCondition(() => {
         return statusDiv.getAttribute("status") == "success";
       }, "Timed out waiting for plugin binding to be in success state");
     });
 
-    let [subject, data] = yield crashReportPromise;
+    let [subject, ] = yield crashReportPromise;
 
     ok(subject instanceof Ci.nsIPropertyBag,
        "The crash report subject should be an nsIPropertyBag.");
 
     let crashData = convertPropertyBag(subject);
     ok(crashData.serverCrashID, "Should have a serverCrashID set.");
 
     // Remove the submitted report file after ensuring it exists.
@@ -206,17 +206,17 @@ add_task(function*() {
     // Then click the button to submit the crash report.
     let buttons = notification.querySelectorAll(".notification-button");
     is(buttons.length, 2, "Should have two buttons.");
 
     // The "Submit Crash Report" button should be the second one.
     let submitButton = buttons[1];
     submitButton.click();
 
-    let [subject, data] = yield crashReportPromise;
+    let [subject, ] = yield crashReportPromise;
 
     ok(subject instanceof Ci.nsIPropertyBag,
        "The crash report subject should be an nsIPropertyBag.");
 
     let crashData = convertPropertyBag(subject);
     ok(crashData.serverCrashID, "Should have a serverCrashID set.");
 
     // Remove the submitted report file after ensuring it exists.
--- a/browser/base/content/test/plugins/browser_pageInfo_plugins.js
+++ b/browser/base/content/test/plugins/browser_pageInfo_plugins.js
@@ -75,17 +75,16 @@ function testPart1a() {
 
   doOnOpenPageInfo(testPart1b);
 }
 
 function testPart1b() {
   let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
   let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
 
-  var qString = "#" + gTestPermissionString.replace(':', '\\:') + "\\#0";
   is(testRadioGroup.selectedItem, testRadioDefault, "part 1b: Test radio group should be set to 'Default'");
   let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
   testRadioGroup.selectedItem = testRadioAllow;
   testRadioAllow.doCommand();
 
   let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
   let secondtestRadioDefault = gPageInfo.document.getElementById(gSecondTestPermissionString + "#0");
   is(secondtestRadioGroup.selectedItem, secondtestRadioDefault, "part 1b: Second Test radio group should be set to 'Default'");
--- a/browser/base/content/test/plugins/browser_pluginnotification.js
+++ b/browser/base/content/test/plugins/browser_pluginnotification.js
@@ -282,18 +282,16 @@ add_task(function* () {
 
   let pluginInfo = yield promiseForPluginInfo("test");
   ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
 
   ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed,
      "Test 19e, Doorhanger should start out dismissed");
 
   yield ContentTask.spawn(gTestBrowser, null, function* () {
-    let doc = content.document;
-    let plugin = doc.getElementById("test");
     let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                        .getInterface(Components.interfaces.nsIDOMWindowUtils);
     utils.sendMouseEvent("mousedown", 50, 50, 0, 1, 0, false, 0, 0);
     utils.sendMouseEvent("mouseup", 50, 50, 0, 1, 0, false, 0, 0);
   });
 
   let condition = () => !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
     PopupNotifications.panel.firstChild;
--- a/browser/base/content/test/plugins/head.js
+++ b/browser/base/content/test/plugins/head.js
@@ -10,18 +10,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 // The blocklist shim running in the content process does not initialize at
 // start up, so it's not active until we load content that needs to do a
 // check. This helper bypasses the delay to get the svc up and running
 // immediately. Note, call this after remote content has loaded.
 function promiseInitContentBlocklistSvc(aBrowser)
 {
   return ContentTask.spawn(aBrowser, {}, function* () {
     try {
-      let bls = Cc["@mozilla.org/extensions/blocklist;1"]
-                          .getService(Ci.nsIBlocklistService);
+      Cc["@mozilla.org/extensions/blocklist;1"]
+        .getService(Ci.nsIBlocklistService);
     } catch (ex) {
       return ex.message;
     }
     return null;
   });
 }
 
 /**
@@ -203,17 +203,16 @@ function promisePlayObject(aId, aBrowser
     objLoadingContent.playPlugin();
   });
 }
 
 function promiseCrashObject(aId, aBrowser) {
   let browser = aBrowser || gTestBrowser;
   return ContentTask.spawn(browser, aId, function* (aId) {
     let plugin = content.document.getElementById(aId);
-    let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
     Components.utils.waiveXrays(plugin).crash();
   });
 }
 
 // Return a promise and call the plugin's getObjectValue() method.
 function promiseObjectValueResult(aId, aBrowser) {
   let browser = aBrowser || gTestBrowser;
   return ContentTask.spawn(browser, aId, function* (aId) {
--- a/browser/base/content/test/popupNotifications/browser_popupNotification_4.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_4.js
@@ -98,17 +98,16 @@ var tests = [
   // Moving a tab to a new window should remove non-swappable notifications.
   { id: "Test#5",
     run: function() {
       gBrowser.selectedTab = gBrowser.addTab("about:blank");
       let notifyObj = new BasicNotification(this.id);
       showNotification(notifyObj);
       let win = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
       whenDelayedStartupFinished(win, function() {
-        let [tab] = win.gBrowser.tabs;
         let anchor = win.document.getElementById("default-notification-icon");
         win.PopupNotifications._reshowNotifications(anchor);
         ok(win.PopupNotifications.panel.childNodes.length == 0,
            "no notification displayed in new window");
         ok(notifyObj.swappingCallbackTriggered, "the swapping callback was triggered");
         ok(notifyObj.removedCallbackTriggered, "the removed callback was triggered");
         win.close();
         goNext();
@@ -127,18 +126,16 @@ var tests = [
       notifyObj.options.eventCallback = function (eventName) {
         originalCallback(eventName);
         return eventName == "swapping";
       };
 
       let notification = showNotification(notifyObj);
       let win = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
       yield whenDelayedStartupFinished(win);
-      let [tab] = win.gBrowser.tabs;
-      let anchor = win.document.getElementById("default-notification-icon");
 
       yield new Promise(resolve => {
         let originalCallback = notification.options.eventCallback;
         notification.options.eventCallback = function (eventName) {
           originalCallback(eventName);
           if (eventName == "shown") {
             resolve();
           }
--- a/browser/base/content/test/social/browser_addons.js
+++ b/browser/base/content/test/social/browser_addons.js
@@ -194,17 +194,16 @@ var tests = {
     AddonManager.addAddonListener(installListener(next, manifest2));
 
     BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown").then(() => {
       let panel = document.getElementById("servicesInstall-notification");
       info("servicesInstall-notification panel opened");
       panel.button.click();
     });
 
-    let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
     Services.prefs.setCharPref("social.directories", manifest2.origin);
     is(SocialService.getOriginActivationType(manifest2.origin), "directory", "testing directory install");
     let data = {
       origin: manifest2.origin,
       url: manifest2.origin + "/directory",
       manifest: manifest2,
       window: window
     }
--- a/browser/base/content/test/social/browser_share.js
+++ b/browser/base/content/test/social/browser_share.js
@@ -113,17 +113,16 @@ var corpus = [
       previews: ["http://example.com/1234/56789.jpg"],
       url: "http://www.example.com/photos/56789/",
       shortUrl: "http://imshort/p/abcde"
     }
   }
 ];
 
 function hasoptions(testOptions, options) {
-  let msg;
   for (let option in testOptions) {
     let data = testOptions[option];
     info("data: "+JSON.stringify(data));
     let message_data = options[option];
     info("message_data: "+JSON.stringify(message_data));
     if (Array.isArray(data)) {
       // the message may have more array elements than we are testing for, this
       // is ok since some of those are hard to test. So we just test that
@@ -177,18 +176,16 @@ var tests = {
         ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
         // button should be visible
         is(shareButton.hidden, false, "share button is visible");
         BrowserTestUtils.removeTab(tab).then(next);
       });
     });
   },
   testSharePage: function(next) {
-    let provider = Social._getProviderFromOrigin(manifest.origin);
-
     let testTab;
     let testIndex = 0;
     let testData = corpus[testIndex++];
 
     // initialize the button into the navbar
     CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
     // ensure correct state
     SocialUI.onCustomizeEnd(window);
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -105,17 +105,16 @@ function runSocialTestWithProvider(manif
       removeProvider(m.origin, callback);
     });
   }
   function finishSocialTest(cleanup) {
     removeAddedProviders(cleanup);
   }
 
   let providersAdded = 0;
-  let firstProvider;
 
   manifests.forEach(function (m) {
     SocialService.addProvider(m, function(provider) {
 
       providersAdded++;
       info("runSocialTestWithProvider: provider added");
 
       // we want to set the first specified provider as the UI's provider
--- a/browser/base/content/test/urlbar/browser_autocomplete_a11y_label.js
+++ b/browser/base/content/test/urlbar/browser_autocomplete_a11y_label.js
@@ -4,17 +4,16 @@
 const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
 const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
 const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
 
 add_task(function* switchToTab() {
   let tab = gBrowser.addTab("about:about");
   yield promiseTabLoaded(tab);
 
-  let actionURL = makeActionURI("switchtab", {url: "about:about"}).spec;
   yield promiseAutocompleteResultPopup("% about");
 
   ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results");
   let result = gURLBar.popup.richlistbox.children[1];
   is(result.getAttribute("type"), "switchtab", "Expect right type attribute");
   is(result.label, "about:about about:about Tab", "Result a11y label should be: <title> <url> Tab");
 
   gURLBar.popup.hidePopup();
--- a/browser/base/content/test/urlbar/browser_bug1104165-switchtab-decodeuri.js
+++ b/browser/base/content/test/urlbar/browser_bug1104165-switchtab-decodeuri.js
@@ -1,15 +1,15 @@
 add_task(function* test_switchtab_decodeuri() {
   info("Opening first tab");
   let tab = gBrowser.addTab("http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html#test%7C1");
   yield promiseTabLoadEvent(tab);
 
   info("Opening and selecting second tab");
-  let newTab = gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedTab = gBrowser.addTab();
 
   info("Wait for autocomplete")
   yield promiseAutocompleteResultPopup("dummy_page");
 
   info("Select autocomplete popup entry");
   EventUtils.synthesizeKey("VK_DOWN", {});
   ok(gURLBar.value.startsWith("moz-action:switchtab"), "switch to tab entry found");
 
--- a/browser/base/content/test/urlbar/browser_search_favicon.js
+++ b/browser/base/content/test/urlbar/browser_search_favicon.js
@@ -20,17 +20,17 @@ add_task(function*() {
   gEngine = Services.search.getEngineByName("SearchEngine");
   gEngine.addParam("q", "{searchTerms}", null);
   gOriginalEngine = Services.search.currentEngine;
   Services.search.currentEngine = gEngine;
 
   let uri = NetUtil.newURI("http://s.example.com/search?q=foo&client=1");
   yield PlacesTestUtils.addVisits({ uri: uri, title: "Foo - SearchEngine Search" });
 
-  let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
+  gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
   yield promiseTabLoaded(gBrowser.selectedTab);
 
   // The first autocomplete result has the action searchengine, while
   // the second result is the "search favicon" element.
   yield promiseAutocompleteResultPopup("foo");
   let result = gURLBar.popup.richlistbox.children[1];
 
   isnot(result, null, "Expect a search result");
--- a/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar_perwindowpb.js
+++ b/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar_perwindowpb.js
@@ -18,17 +18,17 @@ add_task(function*() {
   yield BrowserTestUtils.closeWindow(privateWindow);
 
   normalWindow = yield BrowserTestUtils.openNewBrowserWindow();
   yield runTest(normalWindow, normalWindow, true);
   yield BrowserTestUtils.closeWindow(normalWindow);
 });
 
 function* runTest(aSourceWindow, aDestWindow, aExpectSwitch, aCallback) {
-  let baseTab = yield BrowserTestUtils.openNewForegroundTab(aSourceWindow.gBrowser, testURL);
+  yield BrowserTestUtils.openNewForegroundTab(aSourceWindow.gBrowser, testURL);
   let testTab = yield BrowserTestUtils.openNewForegroundTab(aDestWindow.gBrowser);
 
   info("waiting for focus on the window");
   yield SimpleTest.promiseFocus(aDestWindow);
   info("got focus on the window");
 
   // Select the testTab
   aDestWindow.gBrowser.selectedTab = testTab;
--- a/browser/base/content/test/urlbar/browser_urlbarDecode.js
+++ b/browser/base/content/test/urlbar/browser_urlbarDecode.js
@@ -45,17 +45,17 @@ add_task(function* actionURILosslessDeco
   // simply `url`.  Key down and back around until the heuristic result is
   // selected again, and at that point the urlbar's value should be a visiturl
   // moz-action.
 
   do {
     gURLBar.controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN);
   } while (gURLBar.popup.selectedIndex != 0);
 
-  let [, type, params] = gURLBar.value.match(/^moz-action:([^,]+),(.*)$/);
+  let [, type, ] = gURLBar.value.match(/^moz-action:([^,]+),(.*)$/);
   Assert.equal(type, "visiturl",
                "visiturl action URI should be in the urlbar");
 
   Assert.equal(gURLBar.inputField.value, urlNoScheme,
                "The string displayed in the textbox should not be escaped");
 
   gURLBar.value = "";
   gURLBar.handleRevert();
--- a/browser/base/content/test/urlbar/browser_urlbarEnterAfterMouseOver.js
+++ b/browser/base/content/test/urlbar/browser_urlbarEnterAfterMouseOver.js
@@ -18,17 +18,16 @@ function is_selected(index) {
 let gMaxResults;
 
 add_task(function*() {
   registerCleanupFunction(function* () {
     yield PlacesTestUtils.clearHistory();
   });
 
   yield PlacesTestUtils.clearHistory();
-  let tabCount = gBrowser.tabs.length;
 
   gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
 
   let visits = [];
   repeat(gMaxResults, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
     });
--- a/browser/base/content/test/urlbar/browser_urlbarPrivateBrowsingWindowChange.js
+++ b/browser/base/content/test/urlbar/browser_urlbarPrivateBrowsingWindowChange.js
@@ -2,18 +2,16 @@
 
 /**
  * Test that when opening a private browsing window and typing in it before about:privatebrowsing
  * loads, we don't clear the URL bar.
  */
 add_task(function*() {
   let urlbarTestValue = "Mary had a little lamb";
   let win = OpenBrowserWindow({private: true});
-  let delayedStartupFinished = TestUtils.topicObserved("browser-delayed-startup-finished",
-                                                       subject => subject == win);
   yield BrowserTestUtils.waitForEvent(win, "load");
   let urlbar = win.document.getElementById("urlbar");
   urlbar.value = urlbarTestValue;
   // Need this so the autocomplete controller attaches:
   let focusEv = new FocusEvent("focus", {});
   urlbar.dispatchEvent(focusEv);
   // And so we know input happened:
   let inputEv = new InputEvent("input", {data: "", view: win, bubbles: true});
--- a/browser/base/content/test/urlbar/browser_urlbarSearchSuggestions.js
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchSuggestions.js
@@ -37,17 +37,16 @@ add_task(function* clickSuggestion() {
   Assert.ok(uri.equals(gBrowser.currentURI),
             "The search results page should have loaded");
   gBrowser.removeTab(gBrowser.selectedTab);
 });
 
 function getFirstSuggestion() {
   let controller = gURLBar.popup.input.controller;
   let matchCount = controller.matchCount;
-  let present = false;
   for (let i = 0; i < matchCount; i++) {
     let url = controller.getValueAt(i);
     let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
     if (mozActionMatch) {
       let [, type, paramStr] = mozActionMatch;
       let params = JSON.parse(paramStr);
       if (type == "searchengine" && "searchSuggestion" in params) {
         return [i, params.searchSuggestion, params.engineName];
--- a/browser/base/content/test/urlbar/browser_urlbarSearchSuggestionsNotification.js
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchSuggestionsNotification.js
@@ -216,17 +216,16 @@ function setUserMadeChoicePref(userMadeC
       resolve();
     }
   });
 }
 
 function suggestionsPresent() {
   let controller = gURLBar.popup.input.controller;
   let matchCount = controller.matchCount;
-  let present = false;
   for (let i = 0; i < matchCount; i++) {
     let url = controller.getValueAt(i);
     let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
     if (mozActionMatch) {
       let [, type, paramStr] = mozActionMatch;
       let params = JSON.parse(paramStr);
       if (type == "searchengine" && "searchSuggestion" in params) {
         return true;
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -72,17 +72,16 @@ file, You can obtain one at http://mozil
         this.inputField.controllers.insertControllerAt(0, this._copyCutController);
         this.inputField.addEventListener("paste", this, false);
         this.inputField.addEventListener("mousedown", this, false);
         this.inputField.addEventListener("mousemove", this, false);
         this.inputField.addEventListener("mouseout", this, false);
         this.inputField.addEventListener("overflow", this, false);
         this.inputField.addEventListener("underflow", this, false);
 
-        const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
         var textBox = document.getAnonymousElementByAttribute(this,
                                                 "anonid", "textbox-input-box");
         var cxmenu = document.getAnonymousElementByAttribute(textBox,
                                             "anonid", "input-box-contextmenu");
         var pasteAndGo;
         cxmenu.addEventListener("popupshowing", function() {
           if (!pasteAndGo)
             return;
@@ -2336,17 +2335,17 @@ file, You can obtain one at http://mozil
       </method>
       <method name="_setupSingleState">
         <body><![CDATA[
           var action = this._items[0].action;
           var prePath = action.pluginPermissionPrePath;
           let chromeWin = window.QueryInterface(Ci.nsIDOMChromeWindow);
           let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(chromeWin);
 
-          let label, linkLabel, linkUrl, button1, button2;
+          let label, linkLabel, button1, button2;
 
           if (action.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
             button1 = {
               label: "pluginBlockNow.label",
               accesskey: "pluginBlockNow.accesskey",
               action: "_singleBlock"
             };
             button2 = {
@@ -2463,17 +2462,16 @@ file, You can obtain one at http://mozil
           }
         ]]></body>
       </method>
       <method name="_setupDescription">
         <parameter name="baseString" />
         <parameter name="pluginName" /> <!-- null for the multiple-plugin case -->
         <parameter name="prePath" />
         <body><![CDATA[
-          var bsn = this._brandShortName;
           var span = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-description");
           while (span.lastChild) {
             span.removeChild(span.lastChild);
           }
 
           var args = ["__prepath__", this._brandShortName];
           if (pluginName) {
             args.unshift(pluginName);
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -70,24 +70,18 @@ extensions.on("page-shutdown", (type, co
       let tab = gBrowser.getTabForBrowser(context.xulBrowser);
       if (tab) {
         gBrowser.removeTab(tab);
       }
     }
   }
 });
 
-extensions.on("fill-browser-data", (type, browser, data, result) => {
-  let tabId = TabManager.getBrowserId(browser);
-  if (tabId == -1) {
-    result.cancel = true;
-    return;
-  }
-
-  data.tabId = tabId;
+extensions.on("fill-browser-data", (type, browser, data) => {
+  data.tabId = browser ? TabManager.getBrowserId(browser) : -1;
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 global.currentWindow = function(context) {
   let {xulWindow} = context;
   if (xulWindow && context.viewType != "background") {
     return xulWindow;
   }
--- a/browser/components/migration/360seProfileMigrator.js
+++ b/browser/components/migration/360seProfileMigrator.js
@@ -150,25 +150,25 @@ Bookmarks.prototype = {
               parentGuid =
                 yield MigrationUtils.createImportedBookmarksFolder("360se", parentGuid);
             }
             idToGuid.set("fallback", parentGuid);
           }
 
           try {
             if (is_folder == 1) {
-              let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
+              let newFolderGuid = (yield MigrationUtils.insertBookmarkWrapper({
                 parentGuid,
                 type: PlacesUtils.bookmarks.TYPE_FOLDER,
                 title
               })).guid;
 
               idToGuid.set(id, newFolderGuid);
             } else {
-              yield PlacesUtils.bookmarks.insert({
+              yield MigrationUtils.insertBookmarkWrapper({
                 parentGuid,
                 url,
                 title
               });
             }
           } catch (ex) {
             Cu.reportError(ex);
           }
--- a/browser/components/migration/ChromeProfileMigrator.js
+++ b/browser/components/migration/ChromeProfileMigrator.js
@@ -83,21 +83,21 @@ function* insertBookmarkItems(parentGuid
   for (let item of items) {
     try {
       if (item.type == "url") {
         if (item.url.trim().startsWith("chrome:")) {
           // Skip invalid chrome URIs. Creating an actual URI always reports
           // messages to the console, so we avoid doing that.
           continue;
         }
-        yield PlacesUtils.bookmarks.insert({
+        yield MigrationUtils.insertBookmarkWrapper({
           parentGuid, url: item.url, title: item.name
         });
       } else if (item.type == "folder") {
-        let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
+        let newFolderGuid = (yield MigrationUtils.insertBookmarkWrapper({
           parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: item.name
         })).guid;
 
         yield insertBookmarkItems(newFolderGuid, item.children, errorAccumulator);
       }
     } catch (e) {
       Cu.reportError(e);
       errorAccumulator(e);
@@ -334,17 +334,17 @@ function GetHistoryResource(aProfileFold
             });
           } catch (e) {
             Cu.reportError(e);
           }
         }
 
         if (places.length > 0) {
           yield new Promise((resolve, reject) => {
-            PlacesUtils.asyncHistory.updatePlaces(places, {
+            MigrationUtils.insertVisitsWrapper(places, {
               _success: false,
               handleResult: function() {
                 // Importing any entry is considered a successful import.
                 this._success = true;
               },
               handleError: function() {},
               handleCompletion: function() {
                 if (this._success) {
@@ -442,17 +442,17 @@ function GetWindowsPasswordsResource(aPr
       let crypto = new OSCrypto();
 
       for (let row of rows) {
         let loginInfo = {
           username: row.getResultByName("username_value"),
           password: crypto.
                     decryptData(crypto.arrayToString(row.getResultByName("password_value")),
                                                      null),
-          hostName: NetUtil.newURI(row.getResultByName("origin_url")).prePath,
+          hostname: NetUtil.newURI(row.getResultByName("origin_url")).prePath,
           submitURL: null,
           httpRealm: null,
           usernameElement: row.getResultByName("username_element"),
           passwordElement: row.getResultByName("password_element"),
           timeCreated: chromeTimeToDate(row.getResultByName("date_created") + 0).getTime(),
           timesUsed: row.getResultByName("times_used") + 0,
         };
 
@@ -460,42 +460,23 @@ function GetWindowsPasswordsResource(aPr
           switch (row.getResultByName("scheme")) {
             case AUTH_TYPE.SCHEME_HTML:
               loginInfo.submitURL = NetUtil.newURI(row.getResultByName("action_url")).prePath;
               break;
             case AUTH_TYPE.SCHEME_BASIC:
             case AUTH_TYPE.SCHEME_DIGEST:
               // signon_realm format is URIrealm, so we need remove URI
               loginInfo.httpRealm = row.getResultByName("signon_realm")
-                                    .substring(loginInfo.hostName.length + 1);
+                                       .substring(loginInfo.hostname.length + 1);
               break;
             default:
               throw new Error("Login data scheme type not supported: " +
                               row.getResultByName("scheme"));
           }
-          let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
-
-          login.init(loginInfo.hostName, loginInfo.submitURL, loginInfo.httpRealm,
-                     loginInfo.username, loginInfo.password, loginInfo.usernameElement,
-                     loginInfo.passwordElement);
-          login.QueryInterface(Ci.nsILoginMetaInfo);
-          login.timeCreated = loginInfo.timeCreated;
-          login.timeLastUsed = loginInfo.timeCreated;
-          login.timePasswordChanged = loginInfo.timeCreated;
-          login.timesUsed = loginInfo.timesUsed;
-
-          // Add the login only if there's not an existing entry
-          let logins = Services.logins.findLogins({}, login.hostname,
-                                                  login.formSubmitURL,
-                                                  login.httpRealm);
-
-          // Bug 1187190: Password changes should be propagated depending on timestamps.
-          if (!logins.some(l => login.matches(l, true))) {
-            Services.logins.addLogin(login);
-          }
+          MigrationUtils.insertLoginWrapper(loginInfo);
         } catch (e) {
           Cu.reportError(e);
         }
       }
       crypto.finalize();
       aCallback(true);
     }),
   };
--- a/browser/components/migration/EdgeProfileMigrator.js
+++ b/browser/components/migration/EdgeProfileMigrator.js
@@ -133,17 +133,17 @@ EdgeTypedURLMigrator.prototype = {
       });
     }
 
     if (places.length == 0) {
       aCallback(typedURLs.size == 0);
       return;
     }
 
-    PlacesUtils.asyncHistory.updatePlaces(places, {
+    MigrationUtils.insertVisitsWrapper(places, {
       _success: false,
       handleResult: function() {
         // Importing any entry is considered a successful import.
         this._success = true;
       },
       handleError: function() {},
       handleCompletion: function() {
         aCallback(this._success);
@@ -196,17 +196,17 @@ EdgeReadingListMigrator.prototype = {
     if (!readingListItems.length) {
       return;
     }
 
     let destFolderGuid = yield this._ensureReadingListFolder(parentGuid);
     let exceptionThrown;
     for (let item of readingListItems) {
       let dateAdded = item.AddedDate || new Date();
-      yield PlacesUtils.bookmarks.insert({
+      yield MigrationUtils.insertBookmarkWrapper({
         parentGuid: destFolderGuid, url: item.URL, title: item.Title, dateAdded
       }).catch(ex => {
         if (!exceptionThrown) {
           exceptionThrown = ex;
         }
         Cu.reportError(ex);
       });
     }
@@ -214,17 +214,17 @@ EdgeReadingListMigrator.prototype = {
       throw exceptionThrown;
     }
   }),
 
   _ensureReadingListFolder: Task.async(function*(parentGuid) {
     if (!this.__readingListFolderGuid) {
       let folderTitle = MigrationUtils.getLocalizedString("importedEdgeReadingList");
       let folderSpec = {type: PlacesUtils.bookmarks.TYPE_FOLDER, parentGuid, title: folderTitle};
-      this.__readingListFolderGuid = (yield PlacesUtils.bookmarks.insert(folderSpec)).guid;
+      this.__readingListFolderGuid = (yield MigrationUtils.insertBookmarkWrapper(folderSpec)).guid;
     }
     return this.__readingListFolderGuid;
   }),
 };
 
 function EdgeBookmarksMigrator(dbOverride) {
   this.dbOverride = dbOverride;
 }
@@ -317,17 +317,17 @@ EdgeBookmarksMigrator.prototype = {
       }
       let placesInfo = {
         parentGuid,
         url: bookmark.URL,
         dateAdded: bookmark.DateUpdated || new Date(),
         title: bookmark.Title,
       };
 
-      yield PlacesUtils.bookmarks.insert(placesInfo).catch(ex => {
+      yield MigrationUtils.insertBookmarkWrapper(placesInfo).catch(ex => {
         if (!exceptionThrown) {
           exceptionThrown = ex;
         }
         Cu.reportError(ex);
       });
     }
 
     if (exceptionThrown) {
@@ -385,17 +385,17 @@ EdgeBookmarksMigrator.prototype = {
     let parentGuid = yield this._getGuidForFolder(folder.ParentId, folderMap, rootGuid);
     let folderInfo = {
       title: folder.Title,
       type: PlacesUtils.bookmarks.TYPE_FOLDER,
       dateAdded: folder.DateUpdated || new Date(),
       parentGuid,
     };
     // and add ourselves as a kid, and return the guid we got.
-    let parentBM = yield PlacesUtils.bookmarks.insert(folderInfo);
+    let parentBM = yield MigrationUtils.insertBookmarkWrapper(folderInfo);
     folder._guid = parentBM.guid;
     return folder._guid;
   }),
 };
 
 function EdgeProfileMigrator() {
   this.wrappedJSObject = this;
 }
--- a/browser/components/migration/IEProfileMigrator.js
+++ b/browser/components/migration/IEProfileMigrator.js
@@ -14,17 +14,16 @@ const kMainKey = "Software\\Microsoft\\I
 
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/osfile.jsm"); /* globals OS */
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/MigrationUtils.jsm"); /* globals MigratorPrototype */
 Cu.import("resource:///modules/MSMigrationUtils.jsm");
-Cu.import("resource://gre/modules/LoginHelper.jsm");
 
 
 XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
                                   "resource://gre/modules/ctypes.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OSCrypto",
                                   "resource://gre/modules/OSCrypto.jsm");
@@ -88,17 +87,17 @@ History.prototype = {
     }
 
     // Check whether there is any history to import.
     if (places.length == 0) {
       aCallback(true);
       return;
     }
 
-    PlacesUtils.asyncHistory.updatePlaces(places, {
+    MigrationUtils.insertVisitsWrapper(places, {
       _success: false,
       handleResult: function() {
         // Importing any entry is considered a successful import.
         this._success = true;
       },
       handleError: function() {},
       handleCompletion: function() {
         aCallback(this._success);
@@ -244,17 +243,17 @@ IE7FormPasswords.prototype = {
       try {
         // create a new login
         let login = {
           username: ieLogin.username,
           password: ieLogin.password,
           hostname: ieLogin.url,
           timeCreated: ieLogin.creation,
         };
-        LoginHelper.maybeImportLogin(login);
+        MigrationUtils.insertLoginWrapper(login);
       } catch (e) {
         Cu.reportError(e);
       }
     }
   },
 
   /**
    * Extract the details of one or more logins from the raw decrypted data.
--- a/browser/components/migration/MSMigrationUtils.jsm
+++ b/browser/components/migration/MSMigrationUtils.jsm
@@ -8,17 +8,16 @@ this.EXPORTED_SYMBOLS = ["MSMigrationUti
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource:///modules/MigrationUtils.jsm");
-Cu.import("resource://gre/modules/LoginHelper.jsm");
 
 Cu.importGlobalProperties(["FileReader"]);
 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
                                   "resource://gre/modules/WindowsRegistry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
@@ -402,17 +401,17 @@ Bookmarks.prototype = {
             folderGuid = PlacesUtils.bookmarks.toolbarGuid;
             if (!MigrationUtils.isStartupMigration) {
               folderGuid =
                 yield MigrationUtils.createImportedBookmarksFolder(this.importedAppLabel, folderGuid);
             }
           }
           else {
             // Import to a new folder.
-            folderGuid = (yield PlacesUtils.bookmarks.insert({
+            folderGuid = (yield MigrationUtils.insertBookmarkWrapper({
               type: PlacesUtils.bookmarks.TYPE_FOLDER,
               parentGuid: aDestFolderGuid,
               title: entry.leafName
             })).guid;
           }
 
           if (entry.isReadable()) {
             // Recursively import the folder.
@@ -424,17 +423,17 @@ Bookmarks.prototype = {
           // and get the associated title.
           let matches = entry.leafName.match(/(.+)\.url$/i);
           if (matches) {
             let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
                               getService(Ci.nsIFileProtocolHandler);
             let uri = fileHandler.readURLFile(entry);
             let title = matches[1];
 
-            yield PlacesUtils.bookmarks.insert({
+            yield MigrationUtils.insertBookmarkWrapper({
               parentGuid: aDestFolderGuid, url: uri, title
             });
           }
         }
       } catch (ex) {
         Components.utils.reportError("Unable to import " + this.importedAppLabel + " favorite (" + entry.leafName + "): " + ex);
         succeeded = false;
       }
@@ -833,17 +832,17 @@ WindowsVaultFormPasswords.prototype = {
             // Ignore exceptions in the dates and just create the login for right now.
           }
           // create a new login
           let login = {
             username, password,
             hostname: realURL.prePath,
             timeCreated: creation,
           };
-          LoginHelper.maybeImportLogin(login);
+          MigrationUtils.insertLoginWrapper(login);
 
           // close current item
           error = ctypesVaultHelpers._functions.VaultFree(credential);
           if (error == FREE_CLOSE_FAILED) {
             throw new Error("Unable to free item: " + error);
           }
         } catch (e) {
           migrationSucceeded = false;
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -15,16 +15,18 @@ Cu.import("resource://gre/modules/AppCon
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AutoMigrate",
                                   "resource:///modules/AutoMigrate.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
                                   "resource://gre/modules/BookmarkHTMLUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
+                                  "resource://gre/modules/LoginHelper.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
                                   "resource://gre/modules/PromiseUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
                                   "resource://gre/modules/Sqlite.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
                                   "resource://gre/modules/TelemetryStopwatch.jsm");
@@ -249,16 +251,27 @@ this.MigratorPrototype = {
     };
     let maybeStopTelemetryStopwatch = (resourceType, resource) => {
       let histogram = getHistogramForResourceType(resourceType);
       if (histogram) {
         TelemetryStopwatch.finishKeyed(histogram, this.getKey(), resource);
       }
     };
 
+    let collectQuantityTelemetry = () => {
+      try {
+        for (let resourceType of Object.keys(MigrationUtils._importQuantities)) {
+          let histogramId =
+            "FX_MIGRATION_" + resourceType.toUpperCase() + "_QUANTITY";
+          let histogram = Services.telemetry.getKeyedHistogram(histogramId);
+          histogram.add(this.getKey(), MigrationUtils._importQuantities[resourceType]);
+        }
+      } catch (ex) { /* Telemetry is exception-happy */ }
+    };
+
     // Called either directly or through the bookmarks import callback.
     let doMigrate = Task.async(function*() {
       let resourcesGroupedByItems = new Map();
       resources.forEach(function(resource) {
         if (!resourcesGroupedByItems.has(resource.type)) {
           resourcesGroupedByItems.set(resource.type, new Set());
         }
         resourcesGroupedByItems.get(resource.type).add(resource);
@@ -266,16 +279,19 @@ this.MigratorPrototype = {
 
       if (resourcesGroupedByItems.size == 0)
         throw new Error("No items to import");
 
       let notify = function(aMsg, aItemType) {
         Services.obs.notifyObservers(null, aMsg, aItemType);
       };
 
+      for (let resourceType of Object.keys(MigrationUtils._importQuantities)) {
+        MigrationUtils._importQuantities[resourceType] = 0;
+      }
       notify("Migration:Started");
       for (let [key, value] of resourcesGroupedByItems) {
         // Workaround bug 449811.
         let migrationType = key, itemResources = value;
 
         notify("Migration:ItemBeforeMigrate", migrationType);
 
         let itemSuccess = false;
@@ -289,16 +305,17 @@ this.MigratorPrototype = {
             itemResources.delete(resource);
             itemSuccess |= aSuccess;
             if (itemResources.size == 0) {
               notify(itemSuccess ?
                      "Migration:ItemAfterMigrate" : "Migration:ItemError",
                      migrationType);
               resourcesGroupedByItems.delete(migrationType);
               if (resourcesGroupedByItems.size == 0) {
+                collectQuantityTelemetry();
                 notify("Migration:Ended");
               }
             }
             completeDeferred.resolve();
           };
 
           // If migrate throws, an error occurred, and the callback
           // (itemMayBeDone) might haven't been called.
@@ -669,30 +686,35 @@ this.MigrationUtils = Object.freeze({
    */
   getMigratorKeyForDefaultBrowser() {
     // Canary uses the same description as Chrome so we can't distinguish them.
     const APP_DESC_TO_KEY = {
       "Internet Explorer":                 "ie",
       "Microsoft Edge":                    "edge",
       "Safari":                            "safari",
       "Firefox":                           "firefox",
+      "Nightly":                           "firefox",
       "Google Chrome":                     "chrome",  // Windows, Linux
       "Chrome":                            "chrome",  // OS X
       "Chromium":                          "chromium", // Windows, OS X
       "Chromium Web Browser":              "chromium", // Linux
       "360\u5b89\u5168\u6d4f\u89c8\u5668": "360se",
     };
 
     let key = "";
     try {
       let browserDesc =
         Cc["@mozilla.org/uriloader/external-protocol-service;1"]
           .getService(Ci.nsIExternalProtocolService)
           .getApplicationDescription("http");
       key = APP_DESC_TO_KEY[browserDesc] || "";
+      // Handle devedition, as well as "FirefoxNightly" on OS X.
+      if (!key && browserDesc.startsWith("Firefox")) {
+        key = "firefox";
+      }
     }
     catch (ex) {
       Cu.reportError("Could not detect default browser: " + ex);
     }
 
     // "firefox" is the least useful entry here, and might just be because we've set
     // ourselves as the default (on Windows 7 and below). In that case, check if we
     // have a registry key that tells us where to go:
@@ -902,16 +924,37 @@ this.MigrationUtils = Object.freeze({
       migrator,
       aProfileStartup,
       skipSourcePage,
       aProfileToMigrate,
     ];
     this.showMigrationWizard(null, params);
   },
 
+  _importQuantities: {
+    bookmarks: 0,
+    logins: 0,
+    history: 0,
+  },
+
+  insertBookmarkWrapper(bookmark) {
+    this._importQuantities.bookmarks++;
+    return PlacesUtils.bookmarks.insert(bookmark);
+  },
+
+  insertVisitsWrapper(places, options) {
+    this._importQuantities.history += places.length;
+    return PlacesUtils.asyncHistory.updatePlaces(places, options);
+  },
+
+  insertLoginWrapper(login) {
+    this._importQuantities.logins++;
+    return LoginHelper.maybeImportLogin(login);
+  },
+
   /**
    * Cleans up references to migrators and nsIProfileInstance instances.
    */
   finishMigration: function MU_finishMigration() {
     gMigrators = null;
     gProfileStartup = null;
     gMigrationBundle = null;
   },
--- a/browser/components/migration/SafariProfileMigrator.js
+++ b/browser/components/migration/SafariProfileMigrator.js
@@ -126,17 +126,17 @@ Bookmarks.prototype = {
             yield MigrationUtils.createImportedBookmarksFolder("Safari", folderGuid);
         }
         break;
       }
       case this.READING_LIST_COLLECTION: {
         // Reading list items are imported as regular bookmarks.
         // They are imported under their own folder, created either under the
         // bookmarks menu (in the case of startup migration).
-        folderGuid = (yield PlacesUtils.bookmarks.insert({
+        folderGuid = (yield MigrationUtils.insertBookmarkWrapper({
           parentGuid: PlacesUtils.bookmarks.menuGuid,
           type: PlacesUtils.bookmarks.TYPE_FOLDER,
           title: MigrationUtils.getLocalizedString("importedSafariReadingList"),
         })).guid;
         break;
       }
       default:
         throw new Error("Unexpected value for aCollection!");
@@ -149,31 +149,31 @@ Bookmarks.prototype = {
 
   // migrate the given array of safari bookmarks to the given places
   // folder.
   _migrateEntries: Task.async(function* (entries, parentGuid) {
     for (let entry of entries) {
       let type = entry.get("WebBookmarkType");
       if (type == "WebBookmarkTypeList" && entry.has("Children")) {
         let title = entry.get("Title");
-        let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
+        let newFolderGuid = (yield MigrationUtils.insertBookmarkWrapper({
           parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title
         })).guid;
 
         // Empty folders may not have a children array.
         if (entry.has("Children"))
           yield this._migrateEntries(entry.get("Children"), newFolderGuid, false);
       }
       else if (type == "WebBookmarkTypeLeaf" && entry.has("URLString")) {
         let title;
         if (entry.has("URIDictionary"))
           title = entry.get("URIDictionary").get("title");
 
         try {
-          yield PlacesUtils.bookmarks.insert({
+          yield MigrationUtils.insertBookmarkWrapper({
             parentGuid, url: entry.get("URLString"), title
           });
         } catch (ex) {
           Cu.reportError("Invalid Safari bookmark: " + ex);
         }
       }
     }
   })
@@ -225,17 +225,17 @@ History.prototype = {
             catch (ex) {
               // Safari's History file may contain malformed URIs which
               // will be ignored.
               Cu.reportError(ex);
             }
           }
         }
         if (places.length > 0) {
-          PlacesUtils.asyncHistory.updatePlaces(places, {
+          MigrationUtils.insertVisitsWrapper(places, {
             _success: false,
             handleResult: function() {
               // Importing any entry is considered a successful import.
               this._success = true;
             },
             handleError: function() {},
             handleCompletion: function() {
               aCallback(this._success);
--- a/browser/components/migration/tests/unit/test_Chrome_passwords.js
+++ b/browser/components/migration/tests/unit/test_Chrome_passwords.js
@@ -168,16 +168,18 @@ add_task(function* test_importIntoEmptyD
   let logins = Services.logins.getAllLogins({});
   Assert.equal(logins.length, 0, "There are no logins initially");
 
   // Migrate the logins.
   yield promiseMigration(migrator, MigrationUtils.resourceTypes.PASSWORDS, PROFILE);
 
   logins = Services.logins.getAllLogins({});
   Assert.equal(logins.length, TEST_LOGINS.length, "Check login count after importing the data");
+  Assert.equal(logins.length, MigrationUtils._importQuantities.logins,
+               "Check telemetry matches the actual import.");
 
   for (let i = 0; i < TEST_LOGINS.length; i++) {
     checkLoginsAreEqual(logins[i], TEST_LOGINS[i], i + 1);
   }
 });
 
 // Test that existing logins for the same primary key don't get overwritten
 add_task(function* test_importExistingLogins() {
@@ -203,13 +205,15 @@ add_task(function* test_importExistingLo
     checkLoginsAreEqual(logins[i], newLogins[i], i + 1);
   }
   // Migrate the logins.
   yield promiseMigration(migrator, MigrationUtils.resourceTypes.PASSWORDS, PROFILE);
 
   logins = Services.logins.getAllLogins({});
   Assert.equal(logins.length, TEST_LOGINS.length,
                "Check there are still the same number of logins after re-importing the data");
+  Assert.equal(logins.length, MigrationUtils._importQuantities.logins,
+               "Check telemetry matches the actual import.");
 
   for (let i = 0; i < newLogins.length; i++) {
     checkLoginsAreEqual(logins[i], newLogins[i], i + 1);
   }
 });
--- a/browser/components/migration/tests/unit/test_Edge_db_migration.js
+++ b/browser/components/migration/tests/unit/test_Edge_db_migration.js
@@ -382,16 +382,19 @@ add_task(function*() {
     {type: COLUMN_TYPES.JET_coltypGUID, name: "ParentId"},
   ], itemsInDB);
 
   let migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=edge"]
                  .createInstance(Ci.nsIBrowserProfileMigrator);
   let bookmarksMigrator = migrator.wrappedJSObject.getESEMigratorForTesting(db);
   Assert.ok(bookmarksMigrator.exists, "Should recognize table we just created");
 
+  let source = MigrationUtils.getLocalizedString("sourceNameEdge");
+  let sourceLabel = MigrationUtils.getLocalizedString("importedBookmarksFolder", [source]);
+
   let seenBookmarks = [];
   let bookmarkObserver = {
     onItemAdded(itemId, parentId, index, itemType, url, title, dateAdded, itemGuid, parentGuid) {
       if (title.startsWith("Deleted")) {
         ok(false, "Should not see deleted items being bookmarked!");
       }
       seenBookmarks.push({itemId, parentId, index, itemType, url, title, dateAdded, itemGuid, parentGuid});
     },
@@ -407,16 +410,19 @@ add_task(function*() {
   let migrateResult = yield new Promise(resolve => bookmarksMigrator.migrate(resolve)).catch(ex => {
     Cu.reportError(ex);
     Assert.ok(false, "Got an exception trying to migrate data! " + ex);
     return false;
   });
   PlacesUtils.bookmarks.removeObserver(bookmarkObserver);
   Assert.ok(migrateResult, "Migration should succeed");
   Assert.equal(seenBookmarks.length, 7, "Should have seen 7 items being bookmarked.");
+  Assert.equal(seenBookmarks.filter(bm => bm.title != sourceLabel).length,
+               MigrationUtils._importQuantities.bookmarks,
+               "Telemetry should have items except for 'From Microsoft Edge' folders");
 
   let menuParents = seenBookmarks.filter(item => item.parentGuid == PlacesUtils.bookmarks.menuGuid);
   Assert.equal(menuParents.length, 1, "Should have a single folder added to the menu");
   let toolbarParents = seenBookmarks.filter(item => item.parentGuid == PlacesUtils.bookmarks.toolbarGuid);
   Assert.equal(toolbarParents.length, 1, "Should have a single item added to the toolbar");
   let menuParentGuid = menuParents[0].itemGuid;
   let toolbarParentGuid = toolbarParents[0].itemGuid;
 
--- a/browser/components/migration/tests/unit/test_IE7_passwords.js
+++ b/browser/components/migration/tests/unit/test_IE7_passwords.js
@@ -373,16 +373,25 @@ add_task(function* test_passwordsAvailab
 
     migrator._migrateURIs(uris);
     logins = Services.logins.getAllLogins({});
     // check that the number of logins in the password manager has increased as expected which means
     // that all the values for the current website were imported
     loginCount += website.logins.length;
     Assert.equal(logins.length, loginCount,
                  "The number of logins has increased after the migration");
+    // NB: because telemetry records any login data passed to the login manager, it
+    // also gets told about logins that are duplicates or invalid (for one reason
+    // or another) and so its counts might exceed those of the login manager itself.
+    Assert.greaterOrEqual(MigrationUtils._importQuantities.logins, loginCount,
+                          "Telemetry quantities equal or exceed the actual import.");
+    // Reset - this normally happens at the start of a new migration, but we're calling
+    // the migrator directly so can't rely on that:
+    MigrationUtils._importQuantities.logins = 0;
+
     let startIndex = loginCount - website.logins.length;
     // compares the imported password manager logins with their expected logins
     for (let i = 0; i < website.logins.length; i++) {
       checkLoginsAreEqual(logins[startIndex + i], website.logins[i],
                           " " + current + " - " + i + " ");
     }
   }
 });
--- a/browser/components/migration/tests/unit/test_IE_bookmarks.js
+++ b/browser/components/migration/tests/unit/test_IE_bookmarks.js
@@ -8,31 +8,37 @@ add_task(function* () {
   // Wait for the imported bookmarks.  Check that "From Internet Explorer"
   // folders are created in the menu and on the toolbar.
   let source = MigrationUtils.getLocalizedString("sourceNameIE");
   let label = MigrationUtils.getLocalizedString("importedBookmarksFolder", [source]);
 
   let expectedParents = [ PlacesUtils.bookmarksMenuFolderId,
                           PlacesUtils.toolbarFolderId ];
 
-  PlacesUtils.bookmarks.addObserver({
+  let itemCount = 0;
+  let bmObserver = {
     onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) {
-      if (aTitle == label) {
+      if (aTitle != label) {
+        itemCount++;
+      }
+      if (expectedParents.length > 0 && aTitle == label) {
         let index = expectedParents.indexOf(aParentId);
         Assert.notEqual(index, -1);
         expectedParents.splice(index, 1);
-        if (expectedParents.length == 0)
-          PlacesUtils.bookmarks.removeObserver(this);
       }
     },
     onBeginUpdateBatch() {},
     onEndUpdateBatch() {},
     onItemRemoved() {},
     onItemChanged() {},
     onItemVisited() {},
     onItemMoved() {},
-  }, false);
+  };
+  PlacesUtils.bookmarks.addObserver(bmObserver, false);
 
   yield promiseMigration(migrator, MigrationUtils.resourceTypes.BOOKMARKS);
+  PlacesUtils.bookmarks.removeObserver(bmObserver);
+  Assert.equal(MigrationUtils._importQuantities.bookmarks, itemCount,
+               "Ensure telemetry matches actual number of imported items.");
 
   // Check the bookmarks have been imported to all the expected parents.
-  Assert.equal(expectedParents.length, 0);
+  Assert.equal(expectedParents.length, 0, "Got all the expected parents");
 });
--- a/browser/components/migration/tests/unit/test_Safari_bookmarks.js
+++ b/browser/components/migration/tests/unit/test_Safari_bookmarks.js
@@ -8,32 +8,39 @@ add_task(function* () {
   Assert.ok(migrator.sourceExists);
 
   // Wait for the imported bookmarks.  Check that "From Safari"
   // folders are created on the toolbar.
   let source = MigrationUtils.getLocalizedString("sourceNameSafari");
   let label = MigrationUtils.getLocalizedString("importedBookmarksFolder", [source]);
 
   let expectedParents = [ PlacesUtils.toolbarFolderId ];
+  let itemCount = 0;
 
-  PlacesUtils.bookmarks.addObserver({
+  let bmObserver = {
     onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) {
-      if (aTitle == label) {
+      if (aTitle != label) {
+        itemCount++;
+      }
+      if (expectedParents.length > 0 && aTitle == label) {
         let index = expectedParents.indexOf(aParentId);
-        Assert.notEqual(index, -1);
+        Assert.ok(index != -1, "Found expected parent");
         expectedParents.splice(index, 1);
-        if (expectedParents.length == 0)
-          PlacesUtils.bookmarks.removeObserver(this);
       }
     },
     onBeginUpdateBatch() {},
     onEndUpdateBatch() {},
     onItemRemoved() {},
     onItemChanged() {},
     onItemVisited() {},
     onItemMoved() {},
-  }, false);
+  };
+  PlacesUtils.bookmarks.addObserver(bmObserver, false);
 
   yield promiseMigration(migrator, MigrationUtils.resourceTypes.BOOKMARKS);
+  PlacesUtils.bookmarks.removeObserver(bmObserver);
 
   // Check the bookmarks have been imported to all the expected parents.
-  Assert.equal(expectedParents.length, 0);
+  Assert.ok(!expectedParents.length, "No more expected parents");
+  Assert.equal(itemCount, 13, "Should import all 13 items.");
+  // Check that the telemetry matches:
+  Assert.equal(MigrationUtils._importQuantities.bookmarks, itemCount, "Telemetry reporting correct.");
 });
--- a/browser/components/originattributes/test/browser/head.js
+++ b/browser/components/originattributes/test/browser/head.js
@@ -276,16 +276,21 @@ this.IsolationTestTools = {
    *    An optional function which is called before any tabs are created so
    *    that the test case can set up/reset local state.
    */
   runTests(aURL, aGetResultFuncs, aCompareResultFunc, aBeforeFunc) {
     let pageURL;
     let firstFrameSetting;
     let secondFrameSetting;
 
+    // Request a longer timeout since the test will run a test for three times
+    // with different settings. Thus, one test here represents three tests.
+    // For this reason, we triple the timeout.
+    requestLongerTimeout(3);
+
     if (typeof aURL === "string") {
       pageURL = aURL;
     } else if (typeof aURL === "object") {
       pageURL = aURL.url;
       firstFrameSetting = aURL.firstFrameSetting;
       secondFrameSetting = aURL.secondFrameSetting;
     }
 
--- a/browser/components/places/tests/unit/head_bookmarks.js
+++ b/browser/components/places/tests/unit/head_bookmarks.js
@@ -73,16 +73,20 @@ var createCorruptDB = Task.async(functio
  * exception generated.
  *
  * @return {Promise}
  *         Resolved when done.
  */
 function rebuildSmartBookmarks() {
   let consoleListener = {
     observe(aMsg) {
+      if (aMsg.message.startsWith("[JavaScript Warning:")) {
+        // TODO (Bug 1300416): Ignore spurious strict warnings.
+        return;
+      }
       do_throw("Got console message: " + aMsg.message);
     },
     QueryInterface: XPCOMUtils.generateQI([ Ci.nsIConsoleListener ]),
   };
   Services.console.reset();
   Services.console.registerListener(consoleListener);
   do_register_cleanup(() => {
     try {
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -206,16 +206,20 @@ this.SessionStore = {
   get canRestoreLastSession() {
     return SessionStoreInternal.canRestoreLastSession;
   },
 
   set canRestoreLastSession(val) {
     SessionStoreInternal.canRestoreLastSession = val;
   },
 
+  get lastClosedObjectType() {
+    return SessionStoreInternal.lastClosedObjectType;
+  },
+
   init: function ss_init() {
     SessionStoreInternal.init();
   },
 
   getBrowserState: function ss_getBrowserState() {
     return SessionStoreInternal.getBrowserState();
   },
 
@@ -334,16 +338,20 @@ this.SessionStore = {
   navigateAndRestore(tab, loadArguments, historyIndex) {
     return SessionStoreInternal.navigateAndRestore(tab, loadArguments, historyIndex);
   },
 
   getSessionHistory(tab, updatedCallback) {
     return SessionStoreInternal.getSessionHistory(tab, updatedCallback);
   },
 
+  undoCloseById(aClosedId) {
+    return SessionStoreInternal.undoCloseById(aClosedId);
+  },
+
   /**
    * Determines whether the passed version number is compatible with
    * the current version number of the SessionStore.
    *
    * @param version The format and version of the file, as an array, e.g.
    * ["sessionrestore", 1]
    */
   isFormatVersionCompatible(version) {
@@ -373,16 +381,19 @@ var SessionStoreInternal = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIDOMEventListener,
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ]),
 
   _globalState: new GlobalState(),
 
+  // A counter to be used to generate a unique ID for each closed tab or window.
+  _nextClosedId: 0,
+
   // During the initial restore and setBrowserState calls tracks the number of
   // windows yet to be restored
   _restoreCount: -1,
 
   // For each <browser> element, records the current epoch.
   _browserEpochs: new WeakMap(),
 
   // Any browsers that fires the oop-browser-crashed event gets stored in
@@ -492,16 +503,43 @@ var SessionStoreInternal = {
   set canRestoreLastSession(val) {
     // Cheat a bit; only allow false.
     if (!val) {
       LastSession.clear();
     }
   },
 
   /**
+   * Returns a string describing the last closed object, either "tab" or "window".
+   *
+   * This was added to support the sessions.restore WebExtensions API.
+   */
+  get lastClosedObjectType() {
+    if (this._closedWindows.length) {
+      // Since there are closed windows, we need to check if there's a closed tab
+      // in one of the currently open windows that was closed after the
+      // last-closed window.
+      let tabTimestamps = [];
+      let windowsEnum = Services.wm.getEnumerator("navigator:browser");
+      while (windowsEnum.hasMoreElements()) {
+        let window = windowsEnum.getNext();
+        let windowState = this._windows[window.__SSi];
+        if (windowState && windowState._closedTabs[0]) {
+          tabTimestamps.push(windowState._closedTabs[0].closedAt);
+        }
+      }
+      if (!tabTimestamps.length ||
+          (tabTimestamps.sort((a, b) => b - a)[0] < this._closedWindows[0].closedAt)) {
+        return "window";
+      }
+    }
+    return "tab";
+  },
+
+  /**
    * Initialize the sessionstore service.
    */
   init: function () {
     if (this._initialized) {
       throw new Error("SessionStore.init() must only be called once!");
     }
 
     TelemetryTimestamps.add("sessionRestoreInitialized");
@@ -1426,16 +1464,19 @@ var SessionStoreInternal = {
         });
 
         // If we found no tab closed before our
         // tab then just append it to the list.
         if (index == -1) {
           index = this._closedWindows.length;
         }
 
+        // About to save the closed window, add a unique ID.
+        winData.closedId = this._nextClosedId++;
+
         // Insert tabData at the right position.
         this._closedWindows.splice(index, 0, winData);
         this._capClosedWindows();
       } else if (!shouldStore && alreadyStored) {
         this._closedWindows.splice(winIndex, 1);
       }
     }
   },
@@ -1847,16 +1888,19 @@ var SessionStoreInternal = {
     });
 
     // If we found no tab closed before our
     // tab then just append it to the list.
     if (index == -1) {
       index = closedTabs.length;
     }
 
+    // About to save the closed tab, add a unique ID.
+    tabData.closedId = this._nextClosedId++;
+
     // Insert tabData at the right position.
     closedTabs.splice(index, 0, tabData);
 
     // Truncate the list of closed tabs, if needed.
     if (closedTabs.length > this._max_tabs_undo) {
       closedTabs.splice(this._max_tabs_undo, closedTabs.length);
     }
   },
@@ -2393,16 +2437,52 @@ var SessionStoreInternal = {
   },
 
   persistTabAttribute: function ssi_persistTabAttribute(aName) {
     if (TabAttributes.persist(aName)) {
       this.saveStateDelayed();
     }
   },
 
+
+  /**
+   * Undoes the closing of a tab or window which corresponds
+   * to the closedId passed in.
+   *
+   * @param aClosedId
+   *        The closedId of the tab or window
+   *
+   * @returns a tab or window object
+   */
+  undoCloseById(aClosedId) {
+    // Check for a window first.
+    for (let i = 0, l = this._closedWindows.length; i < l; i++) {
+      if (this._closedWindows[i].closedId == aClosedId) {
+        return this.undoCloseWindow(i);
+      }
+    }
+
+    // Check for a tab.
+    let windowsEnum = Services.wm.getEnumerator("navigator:browser");
+    while (windowsEnum.hasMoreElements()) {
+      let window = windowsEnum.getNext();
+      let windowState = this._windows[window.__SSi];
+      if (windowState) {
+        for (let j = 0, l = windowState._closedTabs.length; j < l; j++) {
+          if (windowState._closedTabs[j].closedId == aClosedId) {
+            return this.undoCloseTab(window, j);
+          }
+        }
+      }
+    }
+
+    // Neither a tab nor a window was found, return undefined and let the caller decide what to do about it.
+    return undefined;
+  },
+
   /**
    * Restores the session state stored in LastSession. This will attempt
    * to merge data into the current session. If a window was opened at startup
    * with pinned tab(s), then the remaining data from the previous session for
    * that window will be opened into that window. Otherwise new windows will
    * be opened.
    */
   restoreLastSession: function ssi_restoreLastSession() {
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -228,9 +228,13 @@ run-if = e10s
 [browser_parentProcessRestoreHash.js]
 run-if = e10s
 [browser_sessionStoreContainer.js]
 [browser_windowStateContainer.js]
 [browser_1234021.js]
 [browser_remoteness_flip_on_restore.js]
 run-if = e10s
 [browser_background_tab_crash.js]
-run-if = e10s && crashreporter
\ No newline at end of file
+run-if = e10s && crashreporter
+
+# Disabled on Linux debug for frequent intermittent failures:
+[browser_undoCloseById.js]
+skip-if = os == "linux" && debug
--- a/browser/components/sessionstore/test/browser_switch_remoteness.js
+++ b/browser/components/sessionstore/test/browser_switch_remoteness.js
@@ -8,18 +8,21 @@ function countHistoryEntries(browser, ex
     let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
     let history = webNavigation.sessionHistory.QueryInterface(Ci.nsISHistoryInternal);
     Assert.equal(history && history.count, args.expected,
       "correct number of shistory entries");
   });
 }
 
 add_task(function* () {
+  // Open a new window.
+  let win = yield promiseNewWindowLoaded();
+
   // Add a new tab.
-  let tab = gBrowser.addTab("about:blank");
+  let tab = win.gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
   ok(browser.isRemoteBrowser, "browser is remote");
 
   // Get the maximum number of preceding entries to save.
   const MAX_BACK = Services.prefs.getIntPref("browser.sessionstore.max_serialize_back");
   ok(MAX_BACK > -1, "check that the default has a value that caps data");
 
@@ -37,10 +40,10 @@ add_task(function* () {
   browser.loadURI("about:robots");
   yield promiseTabRestored(tab);
   ok(!browser.isRemoteBrowser, "browser is not remote anymore");
 
   // Check that we didn't lose any shistory entries.
   yield countHistoryEntries(browser, MAX_BACK + 3);
 
   // Cleanup.
-  gBrowser.removeTab(tab);
+  yield BrowserTestUtils.closeWindow(win);
 });
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_undoCloseById.js
@@ -0,0 +1,118 @@
+"use strict";
+
+/**
+ * This test is for the undoCloseById function.
+ */
+
+Cu.import("resource:///modules/sessionstore/SessionStore.jsm");
+
+function openAndCloseTab(window, url) {
+  let tab = window.gBrowser.addTab(url);
+  yield promiseBrowserLoaded(tab.linkedBrowser, true, url);
+  yield TabStateFlusher.flush(tab.linkedBrowser);
+  yield promiseRemoveTab(tab);
+}
+
+function* openWindow(url) {
+  let win = yield promiseNewWindowLoaded();
+  let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
+  win.gBrowser.selectedBrowser.loadURIWithFlags(url, flags);
+  yield promiseBrowserLoaded(win.gBrowser.selectedBrowser, true, url);
+  return win;
+}
+
+function closeWindow(win) {
+  yield BrowserTestUtils.closeWindow(win);
+  // Wait 20 ms to allow SessionStorage a chance to register the closed window.
+  yield new Promise(resolve => setTimeout(resolve, 20));
+}
+
+add_task(function* test_undoCloseById() {
+  // Clear the lists of closed windows and tabs.
+  forgetClosedWindows();
+  while (SessionStore.getClosedTabCount(window)) {
+    SessionStore.forgetClosedTab(window, 0);
+  }
+
+  // Open a new window.
+  let win = yield openWindow("about:robots");
+
+  // Open and close a tab.
+  yield openAndCloseTab(win, "about:mozilla");
+  is(SessionStore.lastClosedObjectType, "tab", "The last closed object is a tab");
+
+  // Record the first closedId created.
+  let initialClosedId = SessionStore.getClosedTabData(win, false)[0].closedId;
+
+  // Open and close another window.
+  let win2 = yield openWindow("about:mozilla");
+  yield closeWindow(win2);  // closedId == initialClosedId + 1
+  is(SessionStore.lastClosedObjectType, "window", "The last closed object is a window");
+
+  // Open and close another tab in the first window.
+  yield openAndCloseTab(win, "about:robots");  // closedId == initialClosedId + 2
+  is(SessionStore.lastClosedObjectType, "tab", "The last closed object is a tab");
+
+  // Undo closing the second tab.
+  let tab = SessionStore.undoCloseById(initialClosedId + 2);
+  yield promiseBrowserLoaded(tab.linkedBrowser);
+  is(tab.linkedBrowser.currentURI.spec, "about:robots", "The expected tab was re-opened");
+
+  let notTab = SessionStore.undoCloseById(initialClosedId + 2);
+  is(notTab, undefined, "Re-opened tab cannot be unClosed again by closedId");
+
+  // Now the last closed object should be a window again.
+  is(SessionStore.lastClosedObjectType, "window", "The last closed object is a window");
+
+  // Undo closing the first tab.
+  let tab2 = SessionStore.undoCloseById(initialClosedId);
+  yield promiseBrowserLoaded(tab2.linkedBrowser);
+  is(tab2.linkedBrowser.currentURI.spec, "about:mozilla", "The expected tab was re-opened");
+
+  // Close the two tabs we re-opened.
+  yield promiseRemoveTab(tab); // closedId == initialClosedId + 3
+  is(SessionStore.lastClosedObjectType, "tab", "The last closed object is a tab");
+  yield promiseRemoveTab(tab2); // closedId == initialClosedId + 4
+  is(SessionStore.lastClosedObjectType, "tab", "The last closed object is a tab");
+
+  // Open another new window.
+  let win3 = yield openWindow("about:mozilla");
+
+  // Close both windows.
+  yield closeWindow(win); // closedId == initialClosedId + 5
+  is(SessionStore.lastClosedObjectType, "window", "The last closed object is a window");
+  yield closeWindow(win3); // closedId == initialClosedId + 6
+  is(SessionStore.lastClosedObjectType, "window", "The last closed object is a window");
+
+  // Undo closing the second window.
+  win = SessionStore.undoCloseById(initialClosedId + 6);
+  yield BrowserTestUtils.waitForEvent(win, "load");
+
+  // Make sure we wait until this window is restored.
+  yield BrowserTestUtils.waitForEvent(win.gBrowser.tabContainer,
+                                      "SSTabRestored");
+
+  is(win.gBrowser.selectedBrowser.currentURI.spec, "about:mozilla", "The expected window was re-opened");
+
+  let notWin = SessionStore.undoCloseById(initialClosedId + 6);
+  is(notWin, undefined, "Re-opened window cannot be unClosed again by closedId");
+
+  // Close the window again.
+  yield closeWindow(win);
+  is(SessionStore.lastClosedObjectType, "window", "The last closed object is a window");
+
+  // Undo closing the first window.
+  win = SessionStore.undoCloseById(initialClosedId + 5);
+
+  yield BrowserTestUtils.waitForEvent(win, "load");
+
+  // Make sure we wait until this window is restored.
+  yield BrowserTestUtils.waitForEvent(win.gBrowser.tabContainer,
+                                      "SSTabRestored");
+
+  is(win.gBrowser.selectedBrowser.currentURI.spec, "about:robots", "The expected window was re-opened");
+
+  // Close the window again.
+  yield closeWindow(win);
+  is(SessionStore.lastClosedObjectType, "window", "The last closed object is a window");
+});
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -278,18 +278,18 @@ var promiseForEachSessionRestoreFile = T
       if (!(ex instanceof OS.File.Error && ex.becauseNoSuchFile)) {
         throw ex;
       }
     }
     cb(data, key);
   }
 });
 
-function promiseBrowserLoaded(aBrowser, ignoreSubFrames = true) {
-  return BrowserTestUtils.browserLoaded(aBrowser, !ignoreSubFrames);
+function promiseBrowserLoaded(aBrowser, ignoreSubFrames = true, wantLoad = null) {
+  return BrowserTestUtils.browserLoaded(aBrowser, !ignoreSubFrames, wantLoad);
 }
 
 function whenWindowLoaded(aWindow, aCallback = next) {
   aWindow.addEventListener("load", function windowLoadListener() {
     aWindow.removeEventListener("load", windowLoadListener, false);
     executeSoon(function executeWhenWindowLoaded() {
       aCallback(aWindow);
     });
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -5,16 +5,17 @@
 STANDALONE_MAKEFILE := 1
 DIST_SUBDIR := browser
 
 include $(topsrcdir)/config/rules.mk
 
 MOZ_PKG_REMOVALS = $(srcdir)/removed-files.in
 
 MOZ_PKG_MANIFEST = $(srcdir)/package-manifest.in
+MOZ_PKG_DUPEFLAGS = -f $(srcdir)/allowed-dupes.mn
 
 # Some files have been already bundled with xulrunner
 ifndef MOZ_MULET
 MOZ_PKG_FATAL_WARNINGS = 1
 else
 DEFINES += -DMOZ_MULET
 endif
 
new file mode 100644
--- /dev/null
+++ b/browser/installer/allowed-dupes.mn
@@ -0,0 +1,222 @@
+# Known duplicate files
+# This file is ideally removed, but some existing files will be grandfathered in
+# See bug 1303184
+#
+# PLEASE DO NOT ADD MORE EXCEPTIONS TO THIS LIST
+#
+
+# updater on osx is bug 1311194
+LaunchServices/org.mozilla.updater
+updater.app/Contents/MacOS/org.mozilla.updater
+updater.app/Contents/PkgInfo
+browser/chrome.manifest
+# browser branding / themes is bug 1313106
+browser/chrome/browser/content/branding/icon128.png
+browser/chrome/browser/content/branding/icon16.png
+browser/chrome/browser/content/branding/icon32.png
+browser/chrome/browser/content/branding/icon48.png
+browser/chrome/browser/content/browser/defaultthemes/5.footer.png
+browser/chrome/browser/content/browser/defaultthemes/5.header.png
+browser/chrome/browser/content/browser/extension.svg
+browser/chrome/browser/content/browser/places/bookmarkProperties.xul
+browser/chrome/browser/content/browser/places/bookmarkProperties2.xul
+browser/chrome/browser/skin/classic/browser/addons/addon-install-confirm.svg
+browser/chrome/browser/skin/classic/browser/connection-secure.svg
+browser/chrome/browser/skin/classic/browser/controlcenter/warning-gray.svg
+browser/chrome/browser/skin/classic/browser/newtab/close.png
+browser/chrome/browser/skin/classic/browser/theme-switcher-icon.png
+# devtools reduction is bug 1311178
+browser/chrome/devtools/content/dom/content/dom-view.css
+browser/chrome/devtools/content/dom/dom.html
+browser/chrome/devtools/content/dom/main.js
+browser/chrome/devtools/content/framework/toolbox-options.js
+browser/chrome/devtools/content/inspector/fonts/fonts.js
+browser/chrome/devtools/content/inspector/inspector.xhtml
+browser/chrome/devtools/content/memory/initializer.js
+browser/chrome/devtools/content/projecteditor/lib/helpers/readdir.js
+browser/chrome/devtools/content/shared/frame-script-utils.js
+browser/chrome/devtools/content/shared/theme-switching.js
+browser/chrome/devtools/modules/devtools/client/dom/content/dom-view.css
+browser/chrome/devtools/modules/devtools/client/dom/dom.html
+browser/chrome/devtools/modules/devtools/client/dom/main.js
+browser/chrome/devtools/modules/devtools/client/framework/toolbox-options.js
+browser/chrome/devtools/modules/devtools/client/inspector/fonts/fonts.js
+browser/chrome/devtools/modules/devtools/client/inspector/inspector.xhtml
+browser/chrome/devtools/modules/devtools/client/jsonview/css/controls.png
+browser/chrome/devtools/modules/devtools/client/jsonview/css/controls@2x.png
+browser/chrome/devtools/modules/devtools/client/memory/initializer.js
+browser/chrome/devtools/modules/devtools/client/projecteditor/lib/helpers/readdir.js
+browser/chrome/devtools/modules/devtools/client/shared/frame-script-utils.js
+browser/chrome/devtools/modules/devtools/client/shared/theme-switching.js
+browser/chrome/devtools/modules/devtools/client/themes/common.css
+browser/chrome/devtools/modules/devtools/client/themes/variables.css
+browser/chrome/devtools/skin/common.css
+browser/chrome/devtools/skin/images/command-scratchpad.svg
+browser/chrome/devtools/skin/images/controls.png
+browser/chrome/devtools/skin/images/controls@2x.png
+browser/chrome/devtools/skin/images/debugger-blackbox.svg
+browser/chrome/devtools/skin/images/debugger-prettyprint.svg
+browser/chrome/devtools/skin/images/filetypes/store.svg
+browser/chrome/devtools/skin/images/itemToggle.svg
+browser/chrome/devtools/skin/images/security-state-broken.svg
+browser/chrome/devtools/skin/images/security-state-local.svg
+browser/chrome/devtools/skin/images/security-state-secure.svg
+browser/chrome/devtools/skin/images/tabs-icon.svg
+browser/chrome/devtools/skin/images/tool-scratchpad.svg
+browser/chrome/devtools/skin/images/tool-storage.svg
+browser/chrome/devtools/skin/images/tool-styleeditor.svg
+browser/chrome/devtools/skin/promisedebugger.css
+browser/chrome/devtools/skin/variables.css
+modules/devtools/Console.jsm
+modules/devtools/Loader.jsm
+modules/devtools/Simulator.jsm
+modules/devtools/shared/Console.jsm
+modules/devtools/shared/Loader.jsm
+modules/devtools/shared/apps/Simulator.jsm
+browser/modules/devtools/client/framework/gDevTools.jsm
+browser/modules/devtools/gDevTools.jsm
+browser/chrome/icons/default/default16.png
+browser/chrome/icons/default/default32.png
+browser/chrome/icons/default/default48.png
+browser/chrome/pdfjs/content/web/images/findbarButton-next-rtl.png
+browser/chrome/pdfjs/content/web/images/findbarButton-next-rtl@2x.png
+browser/chrome/pdfjs/content/web/images/findbarButton-next.png
+browser/chrome/pdfjs/content/web/images/findbarButton-next@2x.png
+browser/chrome/pdfjs/content/web/images/findbarButton-previous-rtl.png
+browser/chrome/pdfjs/content/web/images/findbarButton-previous-rtl@2x.png
+browser/chrome/pdfjs/content/web/images/findbarButton-previous.png
+browser/chrome/pdfjs/content/web/images/findbarButton-previous@2x.png
+browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/icon.png
+browser/features/firefox@getpocket.com/chrome/skin/linux/menuPanel.png
+browser/features/firefox@getpocket.com/chrome/skin/linux/menuPanel@2x.png
+browser/features/firefox@getpocket.com/chrome/skin/windows/menuPanel.png
+browser/features/firefox@getpocket.com/chrome/skin/windows/menuPanel@2x.png
+# flyweb reduction is bug 1313107
+browser/features/flyweb@mozilla.org/chrome/skin/linux/flyweb.css
+browser/features/flyweb@mozilla.org/chrome/skin/linux/icon-16.png
+browser/features/flyweb@mozilla.org/chrome/skin/linux/icon-32-anchored.png
+browser/features/flyweb@mozilla.org/chrome/skin/linux/icon-32.png
+browser/features/flyweb@mozilla.org/chrome/skin/linux/icon-64-anchored.png
+browser/features/flyweb@mozilla.org/chrome/skin/linux/icon-64.png
+browser/features/flyweb@mozilla.org/chrome/skin/osx/flyweb.css
+browser/features/flyweb@mozilla.org/chrome/skin/osx/icon-32-anchored.png
+browser/features/flyweb@mozilla.org/chrome/skin/osx/icon-64-anchored.png
+browser/features/flyweb@mozilla.org/chrome/skin/windows/flyweb.css
+browser/features/flyweb@mozilla.org/chrome/skin/windows/icon-16.png
+browser/features/flyweb@mozilla.org/chrome/skin/windows/icon-32-anchored.png
+browser/features/flyweb@mozilla.org/chrome/skin/windows/icon-32.png
+browser/features/flyweb@mozilla.org/chrome/skin/windows/icon-64-anchored.png
+browser/features/flyweb@mozilla.org/chrome/skin/windows/icon-64.png
+browser/icons/mozicon128.png
+chrome.manifest
+chrome/en-US/locale/en-US/browser/overrides/AccessFu.properties
+chrome/en-US/locale/en-US/browser/overrides/about.dtd
+chrome/en-US/locale/en-US/browser/overrides/aboutAbout.dtd
+chrome/en-US/locale/en-US/browser/overrides/aboutReader.properties
+chrome/en-US/locale/en-US/browser/overrides/aboutRights.dtd
+chrome/en-US/locale/en-US/browser/overrides/charsetMenu.properties
+chrome/en-US/locale/en-US/browser/overrides/commonDialogs.properties
+chrome/en-US/locale/en-US/browser/overrides/crashreporter/crashes.dtd
+chrome/en-US/locale/en-US/browser/overrides/crashreporter/crashes.properties
+chrome/en-US/locale/en-US/browser/overrides/dom/dom.properties
+chrome/en-US/locale/en-US/browser/overrides/global.dtd
+chrome/en-US/locale/en-US/browser/overrides/global/aboutSupport.dtd
+chrome/en-US/locale/en-US/browser/overrides/global/aboutSupport.properties
+chrome/en-US/locale/en-US/browser/overrides/global/aboutTelemetry.dtd
+chrome/en-US/locale/en-US/browser/overrides/global/aboutTelemetry.properties
+chrome/en-US/locale/en-US/browser/overrides/global/aboutWebrtc.properties
+chrome/en-US/locale/en-US/browser/overrides/global/mozilla.dtd
+chrome/en-US/locale/en-US/browser/overrides/intl.css
+chrome/en-US/locale/en-US/browser/overrides/intl.properties
+chrome/en-US/locale/en-US/browser/overrides/passwordmgr.properties
+chrome/en-US/locale/en-US/browser/overrides/plugins.properties
+chrome/en-US/locale/en-US/browser/overrides/plugins/pluginproblem.dtd
+chrome/en-US/locale/en-US/browser/overrides/search/search.properties
+chrome/en-US/locale/en-US/global-platform/mac/intl.properties
+chrome/en-US/locale/en-US/global-platform/unix/accessible.properties
+chrome/en-US/locale/en-US/global-platform/unix/intl.properties
+chrome/en-US/locale/en-US/global-platform/unix/platformKeys.properties
+chrome/en-US/locale/en-US/global-platform/win/accessible.properties
+chrome/en-US/locale/en-US/global-platform/win/intl.properties
+chrome/en-US/locale/en-US/global-platform/win/platformKeys.properties
+chrome/en-US/locale/en-US/global/AccessFu.properties
+chrome/en-US/locale/en-US/global/about.dtd
+chrome/en-US/locale/en-US/global/aboutAbout.dtd
+chrome/en-US/locale/en-US/global/aboutReader.properties
+chrome/en-US/locale/en-US/global/aboutRights.dtd
+chrome/en-US/locale/en-US/global/aboutSupport.dtd
+chrome/en-US/locale/en-US/global/aboutSupport.properties
+chrome/en-US/locale/en-US/global/aboutTelemetry.dtd
+chrome/en-US/locale/en-US/global/aboutTelemetry.properties
+chrome/en-US/locale/en-US/global/aboutWebrtc.properties
+chrome/en-US/locale/en-US/global/charsetMenu.properties
+chrome/en-US/locale/en-US/global/commonDialogs.properties
+chrome/en-US/locale/en-US/global/crashes.dtd
+chrome/en-US/locale/en-US/global/crashes.properties
+chrome/en-US/locale/en-US/global/dom/dom.properties
+chrome/en-US/locale/en-US/global/global.dtd
+chrome/en-US/locale/en-US/global/intl.css
+chrome/en-US/locale/en-US/global/intl.properties
+chrome/en-US/locale/en-US/global/mozilla.dtd
+chrome/en-US/locale/en-US/global/plugins.properties
+chrome/en-US/locale/en-US/global/search/search.properties
+chrome/en-US/locale/en-US/passwordmgr/passwordmgr.properties
+chrome/en-US/locale/en-US/pluginproblem/pluginproblem.dtd
+chrome/toolkit/skin/classic/global/autocomplete.css
+chrome/toolkit/skin/classic/global/button.css
+chrome/toolkit/skin/classic/global/checkbox.css
+chrome/toolkit/skin/classic/global/dialog.css
+chrome/toolkit/skin/classic/global/dropmarker.css
+chrome/toolkit/skin/classic/global/global.css
+chrome/toolkit/skin/classic/global/groupbox.css
+chrome/toolkit/skin/classic/global/icons/close-XPVista7.png
+chrome/toolkit/skin/classic/global/icons/tabprompts-bgtexture.png
+chrome/toolkit/skin/classic/global/listbox.css
+chrome/toolkit/skin/classic/global/media/clicktoplay-bgtexture.png
+chrome/toolkit/skin/classic/global/menu.css
+chrome/toolkit/skin/classic/global/menulist.css
+chrome/toolkit/skin/classic/global/numberbox.css
+chrome/toolkit/skin/classic/global/popup.css
+chrome/toolkit/skin/classic/global/preferences.css
+chrome/toolkit/skin/classic/global/progressmeter.css
+chrome/toolkit/skin/classic/global/radio.css
+chrome/toolkit/skin/classic/global/resizer.css
+chrome/toolkit/skin/classic/global/richlistbox.css
+chrome/toolkit/skin/classic/global/scale.css
+chrome/toolkit/skin/classic/global/scrollbars.css
+chrome/toolkit/skin/classic/global/scrollbox.css
+chrome/toolkit/skin/classic/global/spinbuttons.css
+chrome/toolkit/skin/classic/global/splitter.css
+chrome/toolkit/skin/classic/global/tabbox.css
+chrome/toolkit/skin/classic/global/textbox.css
+chrome/toolkit/skin/classic/global/toolbar.css
+chrome/toolkit/skin/classic/global/toolbarbutton.css
+chrome/toolkit/skin/classic/global/tree.css
+chrome/toolkit/skin/classic/global/wizard.css
+chrome/toolkit/skin/classic/mozapps/downloads/buttons.png
+chrome/toolkit/skin/classic/mozapps/downloads/downloadButtons-XP.png
+chrome/toolkit/skin/classic/mozapps/downloads/downloadButtons.png
+chrome/toolkit/skin/classic/mozapps/extensions/category-dictionaries.png
+chrome/toolkit/skin/classic/mozapps/extensions/category-experiments.png
+chrome/toolkit/skin/classic/mozapps/extensions/dictionaryGeneric.png
+chrome/toolkit/skin/classic/mozapps/extensions/experimentGeneric.png
+chrome/toolkit/skin/classic/mozapps/update/buttons.png
+chrome/toolkit/skin/classic/mozapps/update/downloadButtons-XP.png
+chrome/toolkit/skin/classic/mozapps/update/downloadButtons.png
+components/FxAccountsPush.js
+crashreporter.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
+crashreporter.app/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib
+# firefox/firefox-bin is bug 658850
+firefox
+firefox-bin
+modules/FxAccountsPush.js
+modules/commonjs/index.js
+modules/commonjs/sdk/ui/button/view/events.js
+modules/commonjs/sdk/ui/state/events.js
+plugin-container.app/Contents/PkgInfo
+res/table-remove-column-active.gif
+res/table-remove-column-hover.gif
+res/table-remove-column.gif
+res/table-remove-row-active.gif
+res/table-remove-row-hover.gif
+res/table-remove-row.gif
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -179,19 +179,16 @@
 @RESPATH@/components/content_xslt.xpt
 @RESPATH@/components/cookie.xpt
 @RESPATH@/components/directory.xpt
 @RESPATH@/components/docshell.xpt
 @RESPATH@/components/dom.xpt
 @RESPATH@/components/dom_apps.xpt
 @RESPATH@/components/dom_base.xpt
 @RESPATH@/components/dom_system.xpt
-#ifdef MOZ_B2G_BT
-@RESPATH@/components/dom_bluetooth.xpt
-#endif
 @RESPATH@/components/dom_canvas.xpt
 @RESPATH@/components/dom_core.xpt
 @RESPATH@/components/dom_css.xpt
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
 @RESPATH@/components/dom_notification.xpt
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -316,16 +316,19 @@ this.PermissionPromptPrototype = {
                 promptAction.action == Ci.nsIPermissionManager.ALLOW_ACTION) {
               this.allow();
             } else {
               this.cancel();
             }
           }
         },
       };
+      if (promptAction.dismiss) {
+        action.dismiss = promptAction.dismiss
+      }
 
       popupNotificationActions.push(action);
     }
 
     let mainAction = popupNotificationActions.length ?
                      popupNotificationActions[0] : null;
     let secondaryActions = popupNotificationActions.splice(1);
 
--- a/browser/modules/URLBarZoom.jsm
+++ b/browser/modules/URLBarZoom.jsm
@@ -6,46 +6,57 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = [ "URLBarZoom" ];
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 var URLBarZoom = {
 
-  init: function(aWindow) {
+  init(aWindow) {
     // Register ourselves with the service so we know when the zoom prefs change.
-    Services.obs.addObserver(updateZoomButton, "browser-fullZoom:zoomChange", false);
-    Services.obs.addObserver(updateZoomButton, "browser-fullZoom:zoomReset", false);
-    Services.obs.addObserver(updateZoomButton, "browser-fullZoom:location-change", false);
+    Services.obs.addObserver(this, "browser-fullZoom:zoomChange", false);
+    Services.obs.addObserver(this, "browser-fullZoom:zoomReset", false);
+    Services.obs.addObserver(this, "browser-fullZoom:location-change", false);
+  },
+
+  observe(aSubject, aTopic) {
+    this.updateZoomButton(aSubject, aTopic);
   },
-}
 
-function updateZoomButton(aSubject, aTopic) {
-  let win = aSubject.ownerDocument.defaultView;
-  let customizableZoomControls = win.document.getElementById("zoom-controls");
-  let zoomResetButton = win.document.getElementById("urlbar-zoom-button");
-  let zoomFactor = Math.round(win.ZoomManager.zoom * 100);
+  updateZoomButton(aSubject, aTopic) {
+    // aSubject.ownerGlobal may no longer exist if a tab has been dragged to a
+    // new window. In this case, aSubject.ownerGlobal will be supplied by
+    // updateZoomButton() called in XULBrowserWindow.onLocationChange().
+    if (!aSubject.ownerGlobal) {
+      return;
+    }
+
+    let win = aSubject.ownerGlobal;
+    let customizableZoomControls = win.document.getElementById("zoom-controls");
+    let zoomResetButton = win.document.getElementById("urlbar-zoom-button");
+    let zoomFactor = Math.round(win.ZoomManager.zoom * 100);
 
-  // Ensure that zoom controls haven't already been added to browser in Customize Mode
-  if (customizableZoomControls &&
-      customizableZoomControls.getAttribute("cui-areatype") == "toolbar") {
-    zoomResetButton.hidden = true;
-    return;
-  }
-  if (zoomFactor != 100) {
-    // Check if zoom button is visible and update label if it is
-    if (zoomResetButton.hidden) {
-      zoomResetButton.hidden = false;
+    // Ensure that zoom controls haven't already been added to browser in Customize Mode
+    if (customizableZoomControls &&
+        customizableZoomControls.getAttribute("cui-areatype") == "toolbar") {
+      zoomResetButton.hidden = true;
+      return;
     }
-    // Only allow pulse animation for zoom changes, not tab switching
-    if (aTopic != "browser-fullZoom:location-change") {
-      zoomResetButton.setAttribute("animate", "true");
+    if (zoomFactor != 100) {
+      // Check if zoom button is visible and update label if it is
+      if (zoomResetButton.hidden) {
+        zoomResetButton.hidden = false;
+      }
+      // Only allow pulse animation for zoom changes, not tab switching
+      if (aTopic != "browser-fullZoom:location-change") {
+        zoomResetButton.setAttribute("animate", "true");
+      } else {
+        zoomResetButton.removeAttribute("animate");
+      }
+      zoomResetButton.setAttribute("label",
+        win.gNavigatorBundle.getFormattedString("urlbar-zoom-button.label", [zoomFactor]));
     } else {
-      zoomResetButton.removeAttribute("animate");
+      // Hide button if zoom is at 100%
+      zoomResetButton.hidden = true;
     }
-    zoomResetButton.setAttribute("label",
-        win.gNavigatorBundle.getFormattedString("urlbar-zoom-button.label", [zoomFactor]));
-  // Hide button if zoom is at 100%
-  } else {
-      zoomResetButton.hidden = true;
-  }
-}
+  },
+};
--- a/browser/modules/test/browser_CaptivePortalWatcher.js
+++ b/browser/modules/test/browser_CaptivePortalWatcher.js
@@ -91,32 +91,56 @@ function ensureNoPortalTab(win) {
 
 function ensureNoPortalNotification(win) {
   let notificationBox =
     win.document.getElementById("high-priority-global-notificationbox");
   is(notificationBox.getNotificationWithValue(PORTAL_NOTIFICATION_VALUE), null,
     "There should be no captive portal notification in the window.");
 }
 
+/**
+ * Some tests open a new window and close it later. When the window is closed,
+ * the original window opened by mochitest gains focus, generating a
+ * xul-window-visible notification. If the next test also opens a new window
+ * before this notification has a chance to fire, CaptivePortalWatcher picks
+ * up the first one instead of the one from the new window. To avoid this
+ * unfortunate intermittent timing issue, we wait for the notification from
+ * the original window every time we close a window that we opened.
+ */
+function waitForXulWindowVisible() {
+  return new Promise(resolve => {
+    Services.obs.addObserver(function observe() {
+      Services.obs.removeObserver(observe, "xul-window-visible");
+      resolve();
+    }, "xul-window-visible", false);
+  });
+}
+
+function* closeWindowAndWaitForXulWindowVisible(win) {
+  let p = waitForXulWindowVisible();
+  yield BrowserTestUtils.closeWindow(win);
+  yield p;
+}
+
 // Each of the test cases below is run twice: once for login-success and once
 // for login-abort (aSuccess set to true and false respectively).
 let testCasesForBothSuccessAndAbort = [
   /**
    * A portal is detected when there's no browser window,
    * then a browser window is opened, then the portal is freed.
    * The portal tab should be added and focused when the window is
    * opened, and closed automatically when the success event is fired.
    */
   function* test_detectedWithNoBrowserWindow_Open(aSuccess) {
     yield portalDetectedNoBrowserWindow();
     let win = yield openWindowAndWaitForPortalTabAndNotification();
     freePortal(aSuccess);
     ensureNoPortalTab(win);
     ensureNoPortalNotification(win);
-    yield BrowserTestUtils.closeWindow(win);
+    yield closeWindowAndWaitForXulWindowVisible(win);
   },
 
   /**
    * A portal is detected when there's no browser window, and the
    * portal is freed before a browser window is opened. No portal
    * tab should be added when a browser window is opened.
    */
   function* test_detectedWithNoBrowserWindow_GoneBeforeOpen(aSuccess) {
@@ -124,17 +148,17 @@ let testCasesForBothSuccessAndAbort = [
     freePortal(aSuccess);
     let win = yield BrowserTestUtils.openNewBrowserWindow();
     // Wait for a while to make sure no tab is opened.
     yield new Promise(resolve => {
       setTimeout(resolve, 1000);
     });
     ensureNoPortalTab(win);
     ensureNoPortalNotification(win);
-    yield BrowserTestUtils.closeWindow(win);
+    yield closeWindowAndWaitForXulWindowVisible(win);
   },
 
   /**
    * A portal is detected when a browser window has focus. A portal tab should be
    * opened in the background in the focused browser window. If the portal is
    * freed when the tab isn't focused, the tab should be closed automatically.
    */
   function* test_detectedWithFocus(aSuccess) {
@@ -186,17 +210,17 @@ let singleRunTestCases = [
     let browser = win.gBrowser.selectedTab.linkedBrowser;
     let loadPromise =
       BrowserTestUtils.browserLoaded(browser, false, CANONICAL_URL_REDIRECTED);
     BrowserTestUtils.loadURI(browser, CANONICAL_URL_REDIRECTED);
     yield loadPromise;
     freePortal(true);
     ensurePortalTab(win);
     ensureNoPortalNotification(win);
-    yield BrowserTestUtils.closeWindow(win);
+    yield closeWindowAndWaitForXulWindowVisible(win);
   },
 
   /**
    * A portal is detected when a browser window has focus. A portal tab should be
    * opened in the background in the focused browser window. If the portal is
    * freed when the tab isn't focused, the tab should be closed automatically,
    * even if the portal has redirected to a URL other than CANONICAL_URL.
    */
--- a/browser/themes/linux/searchbar.css
+++ b/browser/themes/linux/searchbar.css
@@ -118,26 +118,49 @@ menuitem[cmd="cmd_clearhistory"][disable
   }
 
   .search-go-button:hover:active {
     -moz-image-region: rect(56px, 84px, 84px, 56px);
   }
 }
 
 .search-panel-current-engine {
-  border-top: none !important;
   -moz-box-align: center;
 }
 
+/**
+ * The borders of the various elements are specified as follows.
+ *
+ * The current engine always has a bottom border.
+ * The search results never have a border.
+ *
+ * When the search results are not collapsed:
+ * - The elements underneath the search results all have a top border.
+ *
+ * When the search results are collapsed:
+ * - The elements underneath the search results all have a bottom border, except
+ *   the lowest one: search-setting-button.
+ */
+
 .search-panel-current-engine {
-  border-bottom: none;
+  border-top: none !important;
+  border-bottom: 1px solid var(--panel-separator-color) !important;
 }
 
-.search-panel-tree {
-  border-top: 1px solid var(--panel-separator-color) !important;
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-header,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-one-offs,
+.search-panel-tree[collapsed=true] + .search-one-offs > vbox > .addengine-item:first-of-type {
+  border-top: none !important;
+}
+
+.search-panel-tree[collapsed=true] + .search-one-offs > .searchbar-engine-one-off-item,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-current-input,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-one-offs,
+.search-panel-tree[collapsed=true] + .search-one-offs > vbox > .addengine-item:last-of-type {
+  border-bottom: 1px solid var(--panel-separator-color) !important;
 }
 
 .search-panel-header {
   font-weight: normal;
   background-color: var(--arrowpanel-dimmed);
   border: none;
   border-top: 1px solid var(--panel-separator-color);
   padding: 3px 5px;
--- a/browser/themes/osx/searchbar.css
+++ b/browser/themes/osx/searchbar.css
@@ -107,26 +107,49 @@
   }
 
   .searchbar-search-button:hover:active {
     -moz-image-region: rect(0, 120px, 40px, 80px);
   }
 }
 
 .search-panel-current-engine {
-  border-top: none !important;
   border-radius: 4px 4px 0 0;
 }
 
+/**
+ * The borders of the various elements are specified as follows.
+ *
+ * The current engine always has a bottom border.
+ * The search results never have a border.
+ *
+ * When the search results are not collapsed:
+ * - The elements underneath the search results all have a top border.
+ *
+ * When the search results are collapsed:
+ * - The elements underneath the search results all have a bottom border, except
+ *   the lowest one: search-setting-button.
+ */
+
 .search-panel-current-engine {
-  border-bottom: none;
+  border-top: none !important;
+  border-bottom: 1px solid var(--panel-separator-color);
 }
 
-.search-panel-tree {
-  border-top: 1px solid var(--panel-separator-color) !important;
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-header,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-one-offs,
+.search-panel-tree[collapsed=true] + .search-one-offs > vbox > .addengine-item:first-of-type {
+  border-top: none;
+}
+
+.search-panel-tree[collapsed=true] + .search-one-offs > .searchbar-engine-one-off-item,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-current-input,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-one-offs,
+.search-panel-tree[collapsed=true] + .search-one-offs > vbox > .addengine-item:last-of-type {
+  border-bottom: 1px solid var(--panel-separator-color);
 }
 
 .search-panel-header {
   font-size: 10px;
   font-weight: normal;
   background-color: var(--arrowpanel-dimmed);
   border-top: 1px solid var(--panel-separator-color);
   margin: 0;
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -213,16 +213,22 @@
   filter: url(chrome://browser/skin/filters.svg#fill) drop-shadow(1px 1px 1px black);
 }
 
 .tab-icon-sound[soundplaying]:not(:hover),
 .tab-icon-sound[muted]:not(:hover) {
   opacity: .8;
 }
 
+.tab-icon-sound[soundplaying-scheduledremoval]:not(:hover),
+.tab-icon-overlay[soundplaying-scheduledremoval]:not(:hover) {
+  transition: opacity .3s linear var(--soundplaying-removal-delay);
+  opacity: 0;
+}
+
 .tab-background,
 .tabs-newtab-button {
   /* overlap the tab curves */
   margin-inline-end: -@tabCurveHalfWidth@;
   margin-inline-start: -@tabCurveHalfWidth@;
 }
 
 .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox {
--- a/browser/themes/windows/searchbar.css
+++ b/browser/themes/windows/searchbar.css
@@ -113,26 +113,49 @@
   }
 
   .search-go-button:hover:active {
     -moz-image-region: rect(56px, 84px, 84px, 56px);
   }
 }
 
 .search-panel-current-engine {
-  border-top: none !important;
   -moz-box-align: center;
 }
 
+/**
+ * The borders of the various elements are specified as follows.
+ *
+ * The current engine always has a bottom border.
+ * The search results never have a border.
+ *
+ * When the search results are not collapsed:
+ * - The elements underneath the search results all have a top border.
+ *
+ * When the search results are collapsed:
+ * - The elements underneath the search results all have a bottom border, except
+ *   the lowest one: search-setting-button.
+ */
+
 .search-panel-current-engine {
-  border-bottom: none;
+  border-top: none !important;
+  border-bottom: 1px solid var(--panel-separator-color) !important;
 }
 
-.search-panel-tree {
-  border-top: 1px solid var(--panel-separator-color) !important;
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-header,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-one-offs,
+.search-panel-tree[collapsed=true] + .search-one-offs > vbox > .addengine-item:first-of-type {
+  border-top: none !important;
+}
+
+.search-panel-tree[collapsed=true] + .search-one-offs > .searchbar-engine-one-off-item,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-current-input,
+.search-panel-tree[collapsed=true] + .search-one-offs > .search-panel-one-offs,
+.search-panel-tree[collapsed=true] + .search-one-offs > vbox > .addengine-item:last-of-type {
+  border-bottom: 1px solid var(--panel-separator-color) !important;
 }
 
 .search-panel-header {
   font-weight: normal;
   background-color: var(--arrowpanel-dimmed);
   border: none;
   border-top: 1px solid var(--panel-separator-color);
   margin: 0;
--- a/build/moz-automation.mk
+++ b/build/moz-automation.mk
@@ -83,22 +83,16 @@ automation/upload: automation/sdk
 # binaries/libs, and that's what we package/test.
 automation/pretty-package: automation/buildsymbols
 
 # The installer, sdk and packager all run stage-package, and may conflict
 # with each other.
 automation/installer: automation/package
 automation/sdk: automation/installer automation/package
 
-# Universal builds need package staging happening before buildsymbols
-# (bug 834228)
-ifdef UNIVERSAL_BINARY
-automation/buildsymbols: automation/package
-endif
-
 # The 'pretty' versions of targets run before the regular ones to avoid
 # conflicts in writing to the same files.
 automation/installer: automation/pretty-installer
 automation/package: automation/pretty-package
 automation/package-tests: automation/pretty-package-tests
 automation/l10n-check: automation/pretty-l10n-check
 automation/update-packaging: automation/pretty-update-packaging
 
--- a/build/moz.configure/android-ndk.configure
+++ b/build/moz.configure/android-ndk.configure
@@ -9,17 +9,17 @@ js_option('--with-android-ndk', nargs=1,
           help='location where the Android NDK can be found')
 
 js_option('--with-android-toolchain', nargs=1,
           help='location of the Android toolchain')
 
 js_option('--with-android-gnu-compiler-version', nargs=1,
           help='GNU compiler version to use')
 
-min_android_version = dependable('9')
+min_android_version = dependable(lambda: '9')
 
 js_option('--with-android-version',
           nargs=1,
           help='android platform version',
           default=min_android_version)
 
 @depends('--with-android-version', min_android_version)
 @imports(_from='__builtin__', _import='ValueError')
@@ -49,16 +49,17 @@ def ndk(value, build_project):
     if value:
         return value[0]
 
 set_config('ANDROID_NDK', ndk)
 add_old_configure_assignment('android_ndk', ndk)
 
 @depends(target, android_version, ndk)
 @checking('for android platform directory')
+@imports('os')
 def android_platform(target, android_version, ndk):
     if target.os != 'Android':
         return
 
     if 'mips' in target.cpu:
         target_dir_name = 'mips'
     elif 'aarch64' == target.cpu:
         target_dir_name = 'arm64'
@@ -92,16 +93,17 @@ def extra_toolchain_flags(platform_dir):
     if not platform_dir:
         return []
     return ['-idirafter',
             os.path.join(platform_dir, 'usr', 'include')]
 
 @depends(target, host, ndk, '--with-android-toolchain',
          '--with-android-gnu-compiler-version')
 @checking('for the Android toolchain directory', lambda x: x or 'not found')
+@imports('os')
 @imports(_from='mozbuild.shellutil', _import='quote')
 def android_toolchain(target, host, ndk, toolchain, gnu_compiler_version):
     if not ndk:
         return
     if toolchain:
         return toolchain[0]
     else:
         if target.cpu == 'arm' and target.endianness == 'little':
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -7,16 +7,17 @@
 include('util.configure')
 include('checks.configure')
 
 option(env='DIST', nargs=1, help='DIST directory')
 
 # Do not allow objdir == srcdir builds.
 # ==============================================================
 @depends('--help', 'DIST')
+@imports('os')
 def check_build_environment(help, dist):
     topobjdir = os.path.realpath(os.path.abspath('.'))
     topsrcdir = os.path.realpath(os.path.abspath(
         os.path.join(os.path.dirname(__file__), '..', '..')))
 
     if dist:
         dist = normsep(dist[0])
     else:
@@ -628,16 +629,17 @@ def default_project(build_env, help):
 option('--enable-project', nargs=1, default=default_project,
        help='Project to build')
 
 option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1,
        help='External directory containing additional build files')
 
 @depends('--enable-project', '--with-external-source-dir',
          check_build_environment, '--help')
+@imports('os')
 def include_project_configure(project, external_source_dir, build_env, help):
     if not project:
         die('--enable-project is required.')
 
     base_dir = build_env.topsrcdir
     if external_source_dir:
         base_dir = os.path.join(base_dir, external_source_dir[0])
 
@@ -806,11 +808,11 @@ def js_option(*args, **kwargs):
     add_old_configure_arg(js_option)
 
 
 # Bug 1278542: This function is a workaround to resolve
 # |android_ndk_include|'s dependency on 'gonkdir.' The
 # actual implementation is located in b2g/moz.configure.
 # Remove this function as soon as 'android_ndk_include'
 # depends on 'target.'
-@dependable
-def gonkdir():
+@depends('--help')
+def gonkdir(_):
     return None
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -10,16 +10,17 @@ def encoded_open(path, mode):
     encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
     return codecs.open(path, mode, encoding)
 
 
 option(env='AUTOCONF', nargs=1, help='Path to autoconf 2.13')
 
 @depends(mozconfig, 'AUTOCONF')
 @checking('for autoconf')
+@imports('os')
 @imports('re')
 def autoconf(mozconfig, autoconf):
     mozconfig_autoconf = None
     if mozconfig['path']:
         make_extra = mozconfig['make_extra']
         if make_extra:
             for assignment in make_extra:
                 m = re.match('(?:export\s+)?AUTOCONF\s*:?=\s*(.+)$',
@@ -59,30 +60,31 @@ set_config('AUTOCONF', autoconf)
 
 
 @depends('OLD_CONFIGURE', mozconfig, autoconf, check_build_environment, shell,
          old_configure_assignments, build_project)
 @imports(_from='__builtin__', _import='open')
 @imports(_from='__builtin__', _import='print')
 @imports('glob')
 @imports('itertools')
+@imports('os')
 @imports('subprocess')
 # Import getmtime without overwriting the sandbox os.path.
 @imports(_from='os.path', _import='getmtime')
 @imports(_from='mozbuild.shellutil', _import='quote')
 def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
                       old_configure_assignments, build_project):
     # os.path.abspath in the sandbox will ensure forward slashes on Windows,
     # which is actually necessary because this path actually ends up literally
     # as $0, and backslashes there breaks autoconf's detection of the source
     # directory.
     old_configure = os.path.abspath(old_configure[0])
     if build_project == 'js':
         old_configure_dir = os.path.dirname(old_configure)
-        if not old_configure_dir.endswith('/js/src'):
+        if not old_configure_dir.replace(os.sep, '/').endswith('/js/src'):
             old_configure = os.path.join(old_configure_dir, 'js', 'src',
                                          os.path.basename(old_configure))
 
     refresh = True
     if os.path.exists(old_configure):
         mtime = getmtime(old_configure)
         aclocal = os.path.join(build_env.topsrcdir, 'build', 'autoconf',
                                '*.m4')
@@ -402,20 +404,20 @@ def post_old_configure(raw_config):
 
 
 # Assuming no other option is declared after this function, handle the
 # env options that were injected by mozconfig_options by creating dummy
 # Option instances and having the sandbox's CommandLineHelper handle
 # them. We only do so for options that haven't been declared so far,
 # which should be a proxy for the options that old-configure handles
 # and that we don't know anything about.
-@dependable
+@depends('--help')
 @imports('__sandbox__')
 @imports(_from='mozbuild.configure.options', _import='Option')
-def remaining_mozconfig_options():
+def remaining_mozconfig_options(_):
     helper = __sandbox__._helper
     for arg in helper:
         if helper._origins[arg] != 'mozconfig':
             continue
         name = arg.split('=', 1)[0]
         if name.isupper() and name not in __sandbox__._options:
             option = Option(env=name, nargs='*', help=name)
             helper.handle(option)
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -113,16 +113,19 @@ def normalize_path():
             path = normsep(path)
             if quote(path) == path:
                 return path
             size = 0
             while True:
                 out = ctypes.create_unicode_buffer(size)
                 needed = GetShortPathNameW(path, out, size)
                 if size >= needed:
+                    if ' ' in out.value:
+                        die("GetShortPathName returned a long path name. "
+                            "Are 8dot3 filenames disabled?")
                     return normsep(out.value)
                 size = needed
 
     else:
         def normalize_path(path):
             return normsep(path)
 
     return normalize_path
@@ -333,51 +336,43 @@ def namespace(**kwargs):
 # or, for convenience, a @depends function.
 @template
 @imports(_from='inspect', _import='isfunction')
 @imports(_from='mozbuild.configure', _import='SandboxDependsFunction')
 def dependable(obj):
     if isinstance(obj, SandboxDependsFunction):
         return obj
     if isfunction(obj):
-        return depends('--help')(lambda _: obj())
-    return depends('--help')(lambda _: obj)
+        return depends(when=True)(obj)
+    return depends(when=True)(lambda: obj)
 
 
 always = dependable(True)
 never = dependable(False)
 
 
 # Some @depends function return namespaces, and one could want to use one
 # specific attribute from such a namespace as a "value" given to functions
 # such as `set_config`. But those functions do not take immediate values.
 # The `delayed_getattr` function allows access to attributes from the result
 # of a @depends function in a non-immediate manner.
 #   @depends('--option')
 #   def option(value)
 #       return namespace(foo=value)
 #   set_config('FOO', delayed_getattr(option, 'foo')
 @template
-@imports('__sandbox__')
 def delayed_getattr(func, key):
-    deps = __sandbox__._depends.get(func, ())
-    if deps:
-        deps = deps.sandboxed_dependencies
-
-    def result(value, _=None):
+    @depends(func)
+    def result(value):
         # The @depends function we're being passed may have returned
         # None, or an object that simply doesn't have the wanted key.
         # In that case, just return None.
         return getattr(value, key, None)
 
-    # Automatically add a dependency on --help when the given @depends
-    # function itself depends on --help.
-    if __sandbox__._help_option in deps:
-        return depends(func, '--help')(result)
-    return depends(func)(result)
+    return result
 
 
 # Like @depends, but the decorated function is only called if one of the
 # arguments it would be called with has a positive value (bool(value) is True)
 @template
 def depends_if(*args):
     def decorator(func):
         @depends(*args)
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -260,16 +260,17 @@ def vc_path(c_compiler):
         result = next
         if p.lower() == 'bin':
             break
     return result
 
 
 @depends_win(vc_path)
 @checking('for the Debug Interface Access SDK', lambda x: x or 'not found')
+@imports('os')
 def dia_sdk_dir(vc_path):
     if vc_path:
         path = os.path.join(os.path.dirname(vc_path), 'DIA SDK')
         if os.path.isdir(path):
             return path
 
 
 @depends_win(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir)
--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -75,27 +75,26 @@ included_inclnames_to_ignore = set([
     'private/pprio.h',          # NSPR
     'prlink.h',                 # NSPR
     'prlock.h',                 # NSPR
     'prprf.h',                  # NSPR
     'prthread.h',               # NSPR
     'prtypes.h',                # NSPR
     'selfhosted.out.h',         # generated in $OBJDIR
     'shellmoduleloader.out.h',  # generated in $OBJDIR
-    'unicode/locid.h',          # ICU
-    'unicode/numsys.h',         # ICU
     'unicode/timezone.h',       # ICU
     'unicode/ucal.h',           # ICU
     'unicode/uclean.h',         # ICU
     'unicode/ucol.h',           # ICU
     'unicode/udat.h',           # ICU
     'unicode/udatpg.h',         # ICU
     'unicode/uenum.h',          # ICU
     'unicode/unorm.h',          # ICU
     'unicode/unum.h',           # ICU
+    'unicode/unumsys.h',        # ICU
     'unicode/ustring.h',        # ICU
     'unicode/utypes.h',         # ICU
     'vtune/VTuneWrapper.h'      # VTune
 ])
 
 # These files have additional constraints on where they are #included, so we
 # ignore #includes of them when checking #include ordering.
 oddly_ordered_inclnames = set([
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -9,24 +9,26 @@ const promise = require("promise");
 const defer = require("devtools/shared/defer");
 const EventEmitter = require("devtools/shared/event-emitter");
 const Services = require("Services");
 const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "gDevTools",
+  "devtools/client/framework/devtools", true);
 
 const targets = new WeakMap();
 const promiseTargets = new WeakMap();
 
 /**
  * Functions for creating Targets
  */
-exports.TargetFactory = {
+const TargetFactory = exports.TargetFactory = {
   /**
    * Construct a Target
    * @param {XULTab} tab
    *        The tab to use in creating a new target.
    *
    * @return A target object
    */
   forTab: function (tab) {
@@ -449,29 +451,31 @@ TabTarget.prototype = {
    * Listen to the different events.
    */
   _setupListeners: function () {
     this._webProgressListener = new TabWebProgressListener(this);
     this.tab.linkedBrowser.addProgressListener(this._webProgressListener);
     this.tab.addEventListener("TabClose", this);
     this.tab.parentNode.addEventListener("TabSelect", this);
     this.tab.ownerDocument.defaultView.addEventListener("unload", this);
+    this.tab.addEventListener("TabRemotenessChange", this);
   },
 
   /**
    * Teardown event listeners.
    */
   _teardownListeners: function () {
     if (this._webProgressListener) {
       this._webProgressListener.destroy();
     }
 
     this._tab.ownerDocument.defaultView.removeEventListener("unload", this);
     this._tab.removeEventListener("TabClose", this);
     this._tab.parentNode.removeEventListener("TabSelect", this);
+    this._tab.removeEventListener("TabRemotenessChange", this);
   },
 
   /**
    * Setup listeners for remote debugging, updating existing ones as necessary.
    */
   _setupRemoteListeners: function () {
     this.client.addListener("closed", this.destroy);
 
@@ -543,19 +547,48 @@ TabTarget.prototype = {
         break;
       case "TabSelect":
         if (this.tab.selected) {
           this.emit("visible", event);
         } else {
           this.emit("hidden", event);
         }
         break;
+      case "TabRemotenessChange":
+        this.onRemotenessChange();
+        break;
     }
   },
 
+  // Automatically respawn the toolbox when the tab changes between being
+  // loaded within the parent process and loaded from a content process.
+  // Process change can go in both ways.
+  onRemotenessChange: function () {
+    // Responsive design do a crazy dance around tabs and triggers
+    // remotenesschange events. But we should ignore them as at the end
+    // the content doesn't change its remoteness.
+    if (this._tab.isReponsiveDesignMode) {
+      return;
+    }
+
+    // Save a reference to the tab as it will be nullified on destroy
+    let tab = this._tab;
+    let onToolboxDestroyed = (event, target) => {
+      if (target != this) {
+        return;
+      }
+      gDevTools.off("toolbox-destroyed", target);
+
+      // Recreate a fresh target instance as the current one is now destroyed
+      let newTarget = TargetFactory.forTab(tab);
+      gDevTools.showToolbox(newTarget);
+    };
+    gDevTools.on("toolbox-destroyed", onToolboxDestroyed);
+  },
+
   /**
    * Target is not alive anymore.
    */
   destroy: function () {
     // If several things call destroy then we give them all the same
     // destruction promise so we're sure to destroy only once
     if (this._destroyer) {
       return this._destroyer.promise;
--- a/devtools/client/framework/test/browser.ini
+++ b/devtools/client/framework/test/browser.ini
@@ -56,16 +56,18 @@ skip-if = true # Bug 1177463 - Temporari
 [browser_toolbox_options_disable_buttons.js]
 [browser_toolbox_options_disable_cache-01.js]
 [browser_toolbox_options_disable_cache-02.js]
 [browser_toolbox_options_disable_js.js]
 [browser_toolbox_options_enable_serviceworkers_testing.js]
 # [browser_toolbox_raise.js] # Bug 962258
 # skip-if = os == "win"
 [browser_toolbox_ready.js]
+[browser_toolbox_remoteness_change.js]
+run-if = e10s
 [browser_toolbox_select_event.js]
 skip-if = e10s # Bug 1069044 - destroyInspector may hang during shutdown
 [browser_toolbox_selected_tool_unavailable.js]
 [browser_toolbox_sidebar.js]
 [browser_toolbox_sidebar_events.js]
 [browser_toolbox_sidebar_existing_tabs.js]
 [browser_toolbox_sidebar_overflow_menu.js]
 [browser_toolbox_split_console.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/browser_toolbox_remoteness_change.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var {Toolbox} = require("devtools/client/framework/toolbox");
+
+const URL_1 = "about:robots";
+const URL_2 = "data:text/html;charset=UTF-8," +
+  encodeURIComponent("<div id=\"remote-page\">foo</div>");
+
+add_task(function* () {
+  info("Open a tab on a URL supporting only running in parent process");
+  let tab = yield addTab(URL_1);
+  is(tab.linkedBrowser.currentURI.spec, URL_1, "We really are on the expected document");
+  is(tab.linkedBrowser.getAttribute("remote"), "", "And running in parent process");
+
+  let toolbox = yield openToolboxForTab(tab);
+
+  let onToolboxDestroyed = toolbox.once("destroyed");
+  let onToolboxCreated = gDevTools.once("toolbox-created");
+
+  info("Navigate to a URL supporting remote process");
+  let onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+  gBrowser.loadURI(URL_2);
+  yield onLoaded;
+
+  is(tab.linkedBrowser.getAttribute("remote"), "true", "Navigated to a data: URI and switching to remote");
+
+  info("Waiting for the toolbox to be destroyed");
+  yield onToolboxDestroyed;
+
+  info("Waiting for a new toolbox to be created");
+  toolbox = yield onToolboxCreated;
+
+  info("Waiting for the new toolbox to be ready");
+  yield toolbox.once("ready");
+
+  info("Veryify we are inspecting the new document");
+  let console = yield toolbox.selectTool("webconsole");
+  let { jsterm } = console.hud;
+  let url = yield jsterm.execute("document.location.href");
+  is(url.textContent, URL_2, "The console inspects the second document");
+});
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -1,14 +1,12 @@
 /* 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/. */
 
-/* globals template */
-
 "use strict";
 
 const promise = require("promise");
 const Services = require("Services");
 const defer = require("devtools/shared/defer");
 const {Task} = require("devtools/shared/task");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -1,14 +1,13 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-/* globals gDevTools */
 
 "use strict";
 
 const promise = require("promise");
 const Services = require("Services");
 const {Task} = require("devtools/shared/task");
 const {Tools} = require("devtools/client/definitions");
 const {l10n} = require("devtools/shared/inspector/css-logic");
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -487,20 +487,16 @@ netmonitor.toolbar.filterFreetext.key=Cm
 # LOCALIZATION NOTE (netmonitor.toolbar.clear): This is the label displayed
 # in the network toolbar for the "Clear" button.
 netmonitor.toolbar.clear=Clear
 
 # LOCALIZATION NOTE (netmonitor.toolbar.perf): This is the label displayed
 # in the network toolbar for the performance analysis button.
 netmonitor.toolbar.perf=Toggle performance analysis…
 
-# LOCALIZATION NOTE (netmonitor.panesButton.tooltip): This is the tooltip for
-# the button that toggles the panes visible or hidden in the netmonitor UI.
-netmonitor.panesButton.tooltip=Toggle network info
-
 # LOCALIZATION NOTE (netmonitor.summary.url): This is the label displayed
 # in the network details headers tab identifying the URL.
 netmonitor.summary.url=Request URL:
 
 # LOCALIZATION NOTE (netmonitor.summary.method): This is the label displayed
 # in the network details headers tab identifying the method.
 netmonitor.summary.method=Request method:
 
--- a/devtools/client/netmonitor/actions/index.js
+++ b/devtools/client/netmonitor/actions/index.js
@@ -1,8 +1,9 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const filters = require("./filters");
+const sidebar = require("./sidebar");
 
-module.exports = Object.assign({}, filters);
+module.exports = Object.assign({}, filters, sidebar);
--- a/devtools/client/netmonitor/actions/moz.build
+++ b/devtools/client/netmonitor/actions/moz.build
@@ -1,9 +1,10 @@
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
     'filters.js',
-    'index.js'
+    'index.js',
+    'sidebar.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/actions/sidebar.js
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const {
+  DISABLE_TOGGLE_BUTTON,
+  SHOW_SIDEBAR,
+  TOGGLE_SIDEBAR,
+} = require("../constants");
+
+/**
+ * Change ToggleButton disabled state.
+ *
+ * @param {boolean} disabled - expected button disabled state
+ */
+function disableToggleButton(disabled) {
+  return {
+    type: DISABLE_TOGGLE_BUTTON,
+    disabled: disabled,
+  };
+}
+
+/**
+ * Change sidebar visible state.
+ *
+ * @param {boolean} visible - expected sidebar visible state
+ */
+function showSidebar(visible) {
+  return {
+    type: SHOW_SIDEBAR,
+    visible: visible,
+  };
+}
+
+/**
+ * Toggle to show/hide sidebar.
+ */
+function toggleSidebar() {
+  return {
+    type: TOGGLE_SIDEBAR,
+  };
+}
+
+module.exports = {
+  disableToggleButton,
+  showSidebar,
+  toggleSidebar,
+};
--- a/devtools/client/netmonitor/components/moz.build
+++ b/devtools/client/netmonitor/components/moz.build
@@ -1,8 +1,9 @@
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
     'filter-buttons.js',
+    'toggle-button.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/components/toggle-button.js
@@ -0,0 +1,69 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* globals NetMonitorView */
+"use strict";
+
+const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
+const { L10N } = require("../l10n");
+const Actions = require("../actions/index");
+
+// Shortcuts
+const { button } = DOM;
+
+/**
+ * Button used to toggle sidebar
+ */
+function ToggleButton({
+  disabled,
+  onToggle,
+  visible,
+}) {
+  let className = ["devtools-button"];
+  if (!visible) {
+    className.push("pane-collapsed");
+  }
+  let titleMsg = visible ? L10N.getStr("collapseDetailsPane") :
+                           L10N.getStr("expandDetailsPane");
+
+  return button({
+    id: "details-pane-toggle",
+    className: className.join(" "),
+    title: titleMsg,
+    disabled: disabled,
+    tabIndex: "0",
+    onMouseDown: onToggle,
+  });
+}
+
+ToggleButton.propTypes = {
+  disabled: PropTypes.bool.isRequired,
+  onToggle: PropTypes.func.isRequired,
+  visible: PropTypes.bool.isRequired,
+};
+
+module.exports = connect(
+  (state) => ({
+    disabled: state.sidebar.toggleButtonDisabled,
+    visible: state.sidebar.visible,
+  }),
+  (dispatch) => ({
+    onToggle: () => {
+      dispatch(Actions.toggleSidebar());
+
+      let requestsMenu = NetMonitorView.RequestsMenu;
+      let selectedIndex = requestsMenu.selectedIndex;
+
+      // Make sure there's a selection if the button is pressed, to avoid
+      // showing an empty network details pane.
+      if (selectedIndex == -1 && requestsMenu.itemCount) {
+        requestsMenu.selectedIndex = 0;
+      } else {
+        requestsMenu.selectedIndex = -1;
+      }
+    },
+  })
+)(ToggleButton);
--- a/devtools/client/netmonitor/constants.js
+++ b/devtools/client/netmonitor/constants.js
@@ -1,11 +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/. */
 "use strict";
 
 const actionTypes = {
   TOGGLE_FILTER: "TOGGLE_FILTER",
   ENABLE_FILTER_ONLY: "ENABLE_FILTER_ONLY",
+  TOGGLE_SIDEBAR: "TOGGLE_SIDEBAR",
+  SHOW_SIDEBAR: "SHOW_SIDEBAR",
+  DISABLE_TOGGLE_BUTTON: "DISABLE_TOGGLE_BUTTON",
 };
 
 module.exports = actionTypes;
--- a/devtools/client/netmonitor/netmonitor-view.js
+++ b/devtools/client/netmonitor/netmonitor-view.js
@@ -111,20 +111,16 @@ var NetMonitorView = {
   /**
    * Initializes the UI for all the displayed panes.
    */
   _initializePanes: function () {
     dumpn("Initializing the NetMonitorView panes");
 
     this._body = $("#body");
     this._detailsPane = $("#details-pane");
-    this._detailsPaneToggleButton = $("#details-pane-toggle");
-
-    this._collapsePaneString = L10N.getStr("collapseDetailsPane");
-    this._expandPaneString = L10N.getStr("expandDetailsPane");
 
     this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth);
     this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight);
     this.toggleDetailsPane({ visible: false });
 
     // Disable the performance statistics mode.
     if (!Prefs.statistics) {
       $("#request-menu-context-perf").hidden = true;
@@ -138,17 +134,16 @@ var NetMonitorView = {
    */
   _destroyPanes: Task.async(function* () {
     dumpn("Destroying the NetMonitorView panes");
 
     Prefs.networkDetailsWidth = this._detailsPane.getAttribute("width");
     Prefs.networkDetailsHeight = this._detailsPane.getAttribute("height");
 
     this._detailsPane = null;
-    this._detailsPaneToggleButton = null;
 
     for (let p of this._editorPromises.values()) {
       let editor = yield p;
       editor.destroy();
     }
   }),
 
   /**
@@ -167,29 +162,24 @@ var NetMonitorView = {
    *        - visible: true if the pane should be shown, false to hide
    *        - animated: true to display an animation on toggle
    *        - delayed: true to wait a few cycles before toggle
    *        - callback: a function to invoke when the toggle finishes
    * @param number tabIndex [optional]
    *        The index of the intended selected tab in the details pane.
    */
   toggleDetailsPane: function (flags, tabIndex) {
-    let pane = this._detailsPane;
-    let button = this._detailsPaneToggleButton;
-
-    ViewHelpers.togglePane(flags, pane);
+    ViewHelpers.togglePane(flags, this._detailsPane);
 
     if (flags.visible) {
       this._body.classList.remove("pane-collapsed");
-      button.classList.remove("pane-collapsed");
-      button.setAttribute("tooltiptext", this._collapsePaneString);
+      gStore.dispatch(Actions.showSidebar(true));
     } else {
       this._body.classList.add("pane-collapsed");
-      button.classList.add("pane-collapsed");
-      button.setAttribute("tooltiptext", this._expandPaneString);
+      gStore.dispatch(Actions.showSidebar(false));
     }
 
     if (tabIndex !== undefined) {
       $("#event-details-pane").selectedIndex = tabIndex;
     }
   },
 
   /**
@@ -284,19 +274,16 @@ var NetMonitorView = {
     let editor = new Editor(DEFAULT_EDITOR_CONFIG);
     editor.appendTo($(id)).then(() => deferred.resolve(editor));
 
     return deferred.promise;
   },
 
   _body: null,
   _detailsPane: null,
-  _detailsPaneToggleButton: null,
-  _collapsePaneString: "",
-  _expandPaneString: "",
   _editorPromises: new Map()
 };
 
 /**
  * Functions handling the sidebar details view.
  */
 function SidebarView() {
   dumpn("SidebarView was instantiated");
--- a/devtools/client/netmonitor/netmonitor.xul
+++ b/devtools/client/netmonitor/netmonitor.xul
@@ -31,21 +31,18 @@
         <toolbarbutton id="requests-menu-network-summary-button"
                        class="devtools-toolbarbutton icon-and-text"
                        data-localization="tooltiptext=netmonitor.toolbar.perf"/>
         <textbox id="requests-menu-filter-freetext-text"
                  class="devtools-filterinput"
                  type="search"
                  required="true"
                  data-localization="placeholder=netmonitor.toolbar.filterFreetext.label"/>
-        <toolbarbutton id="details-pane-toggle"
-                       class="devtools-toolbarbutton"
-                       data-localization="tooltiptext=netmonitor.panesButton.tooltip"
-                       disabled="true"
-                       tabindex="0"/>
+        <html:div xmlns="http://www.w3.org/1999/xhtml"
+                  id="react-details-pane-toggle-hook"/>
       </hbox>
       <hbox id="network-table-and-sidebar"
             class="devtools-responsive-container"
             flex="1">
         <vbox id="network-table" flex="1" class="devtools-main-content">
           <toolbar id="requests-menu-toolbar"
                    class="devtools-toolbar"
                    align="center">
--- a/devtools/client/netmonitor/reducers/index.js
+++ b/devtools/client/netmonitor/reducers/index.js
@@ -1,11 +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/. */
 "use strict";
 
 const { combineReducers } = require("devtools/client/shared/vendor/redux");
 const filters = require("./filters");
+const sidebar = require("./sidebar");
 
 module.exports = combineReducers({
   filters,
+  sidebar,
 });
--- a/devtools/client/netmonitor/reducers/moz.build
+++ b/devtools/client/netmonitor/reducers/moz.build
@@ -1,9 +1,10 @@
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
     'filters.js',
-    'index.js'
+    'index.js',
+    'sidebar.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/reducers/sidebar.js
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const I = require("devtools/client/shared/vendor/immutable");
+const {
+  DISABLE_TOGGLE_BUTTON,
+  SHOW_SIDEBAR,
+  TOGGLE_SIDEBAR,
+} = require("../constants");
+
+const SidebarState = I.Record({
+  toggleButtonDisabled: true,
+  visible: false,
+});
+
+function disableToggleButton(state, action) {
+  return state.set("toggleButtonDisabled", action.disabled);
+}
+
+function showSidebar(state, action) {
+  return state.set("visible", action.visible);
+}
+
+function toggleSidebar(state, action) {
+  return state.set("visible", !state.visible);
+}
+
+function sidebar(state = new SidebarState(), action) {
+  switch (action.type) {
+    case DISABLE_TOGGLE_BUTTON:
+      return disableToggleButton(state, action);
+    case SHOW_SIDEBAR:
+      return showSidebar(state, action);
+    case TOGGLE_SIDEBAR:
+      return toggleSidebar(state, action);
+    default:
+      return state;
+  }
+}
+
+module.exports = sidebar;
--- a/devtools/client/netmonitor/requests-menu-view.js
+++ b/devtools/client/netmonitor/requests-menu-view.js
@@ -122,16 +122,18 @@ function RequestsMenuView() {
 
 RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
   /**
    * Initialization function, called when the network monitor is started.
    */
   initialize: function (store) {
     dumpn("Initializing the RequestsMenuView");
 
+    this.store = store;
+
     let widgetParentEl = $("#requests-menu-contents");
     this.widget = new SideMenuWidget(widgetParentEl);
     this._splitter = $("#network-inspector-view-splitter");
     this._summary = $("#requests-menu-network-summary-button");
     this._summary.setAttribute("label", L10N.getStr("networkMenu.empty"));
     this.userInputTimer = Cc["@mozilla.org/timer;1"]
       .createInstance(Ci.nsITimer);
 
@@ -760,17 +762,17 @@ RequestsMenuView.prototype = Heritage.ex
 
   /**
    * Removes all network requests and closes the sidebar if open.
    */
   clear: function () {
     NetMonitorController.NetworkEventsHandler.clearMarkers();
     NetMonitorView.Sidebar.toggle(false);
 
-    $("#details-pane-toggle").disabled = true;
+    this.store.dispatch(Actions.disableToggleButton(true));
     $("#requests-menu-empty-notice").hidden = false;
 
     this.empty();
     this.refreshSummary();
   },
 
   /**
    * Refreshes the status displayed in this container's footer, providing
@@ -1073,17 +1075,17 @@ RequestsMenuView.prototype = Heritage.ex
         NetMonitorView.NetworkDetails.populate(selectedItem.attachment);
       }
     }
 
     // We're done flushing all the requests, clear the update queue.
     this._updateQueue = [];
     this._addQueue = [];
 
-    $("#details-pane-toggle").disabled = !this.itemCount;
+    this.store.dispatch(Actions.disableToggleButton(!this.itemCount));
     $("#requests-menu-empty-notice").hidden = !!this.itemCount;
 
     // Make sure all the requests are sorted and filtered.
     // Freshly added requests may not yet contain all the information required
     // for sorting and filtering predicates, so this is done each time the
     // network requests table is flushed (don't worry, events are drained first
     // so this doesn't happen once per network event update).
     this.sortContents();
--- a/devtools/client/netmonitor/toolbar-view.js
+++ b/devtools/client/netmonitor/toolbar-view.js
@@ -1,38 +1,38 @@
 /* globals dumpn, $, NetMonitorView */
 "use strict";
 
 const { createFactory, DOM } = require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
 const FilterButtons = createFactory(require("./components/filter-buttons"));
+const ToggleButton = createFactory(require("./components/toggle-button"));
 const { L10N } = require("./l10n");
 
 // Shortcuts
 const { button } = DOM;
 
 /**
  * Functions handling the toolbar view: expand/collapse button etc.
  */
 function ToolbarView() {
   dumpn("ToolbarView was instantiated");
-
-  this._onTogglePanesPressed = this._onTogglePanesPressed.bind(this);
 }
 
 ToolbarView.prototype = {
   /**
    * Initialization function, called when the debugger is started.
    */
   initialize: function (store) {
     dumpn("Initializing the ToolbarView");
 
     this._clearContainerNode = $("#react-clear-button-hook");
     this._filterContainerNode = $("#react-filter-buttons-hook");
+    this._toggleContainerNode = $("#react-details-pane-toggle-hook");
 
     // clear button
     ReactDOM.render(button({
       id: "requests-menu-clear-button",
       className: "devtools-button devtools-clear-icon",
       title: L10N.getStr("netmonitor.toolbar.clear"),
       onClick: () => {
         NetMonitorView.RequestsMenu.clear();
@@ -40,46 +40,27 @@ ToolbarView.prototype = {
     }), this._clearContainerNode);
 
     // filter button
     ReactDOM.render(Provider(
       { store },
       FilterButtons()
     ), this._filterContainerNode);
 
-    this._detailsPaneToggleButton = $("#details-pane-toggle");
-    this._detailsPaneToggleButton.addEventListener("mousedown",
-      this._onTogglePanesPressed, false);
+    ReactDOM.render(Provider(
+      { store },
+      ToggleButton()
+    ), this._toggleContainerNode);
   },
 
   /**
    * Destruction function, called when the debugger is closed.
    */
   destroy: function () {
     dumpn("Destroying the ToolbarView");
 
     ReactDOM.unmountComponentAtNode(this._clearContainerNode);
     ReactDOM.unmountComponentAtNode(this._filterContainerNode);
-
-    this._detailsPaneToggleButton.removeEventListener("mousedown",
-      this._onTogglePanesPressed, false);
-  },
-
-  /**
-   * Listener handling the toggle button click event.
-   */
-  _onTogglePanesPressed: function () {
-    let requestsMenu = NetMonitorView.RequestsMenu;
-    let selectedIndex = requestsMenu.selectedIndex;
-
-    // Make sure there's a selection if the button is pressed, to avoid
-    // showing an empty network details pane.
-    if (selectedIndex == -1 && requestsMenu.itemCount) {
-      requestsMenu.selectedIndex = 0;
-    } else {
-      requestsMenu.selectedIndex = -1;
-    }
-  },
-
-  _detailsPaneToggleButton: null
+    ReactDOM.unmountComponentAtNode(this._toggleContainerNode);
+  }
 };
 
 exports.ToolbarView = ToolbarView;
--- a/devtools/client/responsive.html/browser/swap.js
+++ b/devtools/client/responsive.html/browser/swap.js
@@ -47,16 +47,18 @@ function swapToInnerBrowser({ tab, conta
       bubbles: true,
     });
     from.dispatchEvent(event);
   };
 
   return {
 
     start: Task.async(function* () {
+      tab.isReponsiveDesignMode = true;
+
       // Freeze navigation temporarily to avoid "blinking" in the location bar.
       freezeNavigationState(tab);
 
       // 1. Create a temporary, hidden tab to load the tool UI.
       let containerTab = gBrowser.addTab(containerURL, {
         skipAnimation: true,
       });
       gBrowser.hideTab(containerTab);
@@ -145,16 +147,18 @@ function swapToInnerBrowser({ tab, conta
       dispatchDevToolsBrowserSwap(contentBrowser, tab.linkedBrowser);
       gBrowser.swapBrowsersAndCloseOther(tab, contentTab);
       gBrowser = null;
 
       // The focus manager seems to get a little dizzy after all this swapping.  If a
       // content element had been focused inside the viewport before stopping, it will
       // have lost focus.  Activate the frame to restore expected focus.
       tab.linkedBrowser.frameLoader.activateRemoteFrame();
+
+      delete tab.isReponsiveDesignMode;
     },
 
   };
 }
 
 /**
  * Browser navigation properties we'll freeze temporarily to avoid "blinking" in the
  * location bar, etc. caused by the containerURL peeking through before the swap is
--- a/devtools/client/themes/netmonitor.css
+++ b/devtools/client/themes/netmonitor.css
@@ -2,17 +2,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/. */
 
 #toolbar-labels {
   overflow: hidden;
 }
 
-#react-clear-button-hook {
+#react-clear-button-hook,
+#react-details-pane-toggle-hook {
   display: flex;
 }
 
 /**
  * Collapsed details pane needs to be truly hidden to prevent both accessibility
  * tools and keyboard from accessing its contents.
  */
 #details-pane.pane-collapsed {
@@ -563,24 +564,24 @@
 /* Size Column */
 .theme-firebug .requests-menu-subitem.requests-menu-size {
   text-align: end;
   padding-inline-end: 4px;
 }
 
 /* Network request details */
 
-#details-pane-toggle:-moz-locale-dir(ltr),
-#details-pane-toggle.pane-collapsed:-moz-locale-dir(rtl) {
-  list-style-image: var(--theme-pane-collapse-image);
+#details-pane-toggle:-moz-locale-dir(ltr)::before,
+#details-pane-toggle.pane-collapsed:-moz-locale-dir(rtl)::before {
+  background-image: var(--theme-pane-collapse-image);
 }
 
-#details-pane-toggle.pane-collapsed:-moz-locale-dir(ltr),
-#details-pane-toggle:-moz-locale-dir(rtl) {
-  list-style-image: var(--theme-pane-expand-image);
+#details-pane-toggle.pane-collapsed:-moz-locale-dir(ltr)::before,
+#details-pane-toggle:-moz-locale-dir(rtl)::before {
+  background-image: var(--theme-pane-expand-image);
 }
 
 /* Network request details tabpanels */
 
 .tabpanel-content {
   background-color: var(--theme-sidebar-background);
 }
 
--- a/devtools/shared/touch/simulator-core.js
+++ b/devtools/shared/touch/simulator-core.js
@@ -138,18 +138,17 @@ SimulatorCore.prototype = {
       case "mouseleave":
         // Don't propagate events which are not related to touch events
         evt.stopPropagation();
         break;
 
       case "mousedown":
         this.target = evt.target;
 
-        this.contextMenuTimeout =
-          this.sendContextMenu(evt.target, evt.pageX, evt.pageY);
+        this.contextMenuTimeout = this.sendContextMenu(evt);
 
         this.cancelClick = false;
         this.startX = evt.pageX;
         this.startY = evt.pageY;
 
         // Capture events so if a different window show up the events
         // won't be dispatched to something else.
         evt.target.setCapture(false);
@@ -230,23 +229,28 @@ SimulatorCore.prototype = {
   fireMouseEvent(type, evt) {
     let content = this.getContent(evt.target);
     let utils = content.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDOMWindowUtils);
     utils.sendMouseEvent(type, evt.clientX, evt.clientY, 0, 1, 0, true, 0,
                          Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH);
   },
 
-  sendContextMenu(target, x, y) {
-    let doc = target.ownerDocument;
-    let evt = doc.createEvent("MouseEvent");
-    evt.initMouseEvent("contextmenu", true, true, doc.defaultView,
-                       0, x, y, x, y, false, false, false, false,
-                       0, null);
-
+  sendContextMenu({ target, clientX, clientY, screenX, screenY }) {
+    let view = target.ownerDocument.defaultView;
+    let { MouseEvent } = view;
+    let evt = new MouseEvent("contextmenu", {
+      bubbles: true,
+      cancelable: true,
+      view,
+      screenX,
+      screenY,
+      clientX,
+      clientY,
+    });
     let content = this.getContent(target);
     let timeout = content.setTimeout((function contextMenu() {
       target.dispatchEvent(evt);
       this.cancelClick = true;
     }).bind(this), delay);
 
     return timeout;
   },
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -131,21 +131,16 @@ this.PermissionsTable =  { geolocation: 
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "browser:embedded-system-app": {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
-                           bluetooth: {
-                             app: DENY_ACTION,
-                             privileged: DENY_ACTION,
-                             certified: ALLOW_ACTION
-                           },
                            mobileconnection: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            mobilenetwork: {
                              app: DENY_ACTION,
                              privileged: ALLOW_ACTION,
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -70,29 +70,16 @@ enum DOM4ErrorTypeCodeMap {
   NotReadableError         = 0,
 
   /* FileHandle API errors */
   FileHandleInactiveError = 0,
 
   /* WebCrypto errors https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-DataError */
   OperationError           = 0,
 
-  /* Bluetooth API errors */
-  BtFailError              = 0,
-  BtNotReadyError          = 0,
-  BtNoMemError             = 0,
-  BtBusyError              = 0,
-  BtDoneError              = 0,
-  BtUnsupportedError       = 0,
-  BtParmInvalidError       = 0,
-  BtUnhandledError         = 0,
-  BtAuthFailureError       = 0,
-  BtRmtDevDownError        = 0,
-  BtAuthRejectedError      = 0,
-
   /* Push API errors */
   NotAllowedError          = 0,
 };
 
 #define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message},
 #define DOM_MSG_DEF(val, message) {(val), NS_ERROR_GET_CODE(val), #val, message},
 
 static const struct ResultStruct
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -74,19 +74,16 @@
 #include "nsStreamUtils.h"
 #include "nsIAppsService.h"
 #include "mozIApplication.h"
 #include "WidgetUtils.h"
 #include "nsIPresentationService.h"
 
 #include "mozilla/dom/MediaDevices.h"
 #include "MediaManager.h"
-#ifdef MOZ_B2G_BT
-#include "BluetoothManager.h"
-#endif
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 #include "AudioChannelManager.h"
 #endif
 
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsJSUtils.h"
 
@@ -216,19 +213,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
 #ifdef MOZ_B2G_RIL
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
 #endif
-#ifdef MOZ_B2G_BT
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
-#endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
 #endif
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
@@ -299,22 +293,16 @@ Navigator::Invalidate()
   }
 
 #ifdef MOZ_B2G_RIL
   if (mMobileConnections) {
     mMobileConnections = nullptr;
   }
 #endif
 
-#ifdef MOZ_B2G_BT
-  if (mBluetooth) {
-    mBluetooth = nullptr;
-  }
-#endif
-
   mMediaDevices = nullptr;
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   if (mAudioChannelManager) {
     mAudioChannelManager = nullptr;
   }
 #endif
 
@@ -1795,32 +1783,16 @@ Navigator::GetConnection(ErrorResult& aR
       return nullptr;
     }
     mConnection = new network::Connection(mWindow);
   }
 
   return mConnection;
 }
 
-#ifdef MOZ_B2G_BT
-bluetooth::BluetoothManager*
-Navigator::GetMozBluetooth(ErrorResult& aRv)
-{
-  if (!mBluetooth) {
-    if (!mWindow) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
-    mBluetooth = bluetooth::BluetoothManager::Create(mWindow);
-  }
-
-  return mBluetooth;
-}
-#endif //MOZ_B2G_BT
-
 #ifdef MOZ_TIME_MANAGER
 time::TimeManager*
 Navigator::GetMozTime(ErrorResult& aRv)
 {
   if (!mWindow) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -67,22 +67,16 @@ class GamepadServiceTest;
 class NavigatorUserMediaSuccessCallback;
 class NavigatorUserMediaErrorCallback;
 class MozGetUserMediaDevicesSuccessCallback;
 
 namespace network {
 class Connection;
 } // namespace network
 
-#ifdef MOZ_B2G_BT
-namespace bluetooth {
-class BluetoothManager;
-} // namespace bluetooth
-#endif // MOZ_B2G_BT
-
 #ifdef MOZ_B2G_RIL
 class MobileConnectionArray;
 #endif
 
 class PowerManager;
 class IccManager;
 class InputPortManager;
 class DeviceStorageAreaListener;
@@ -230,19 +224,16 @@ public:
   MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
 #endif // MOZ_B2G_RIL
 #ifdef MOZ_GAMEPAD
   void GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
   GamepadServiceTest* RequestGamepadServiceTest();
 #endif // MOZ_GAMEPAD
   already_AddRefed<Promise> GetVRDisplays(ErrorResult& aRv);
   void GetActiveVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays) const;
-#ifdef MOZ_B2G_BT
-  bluetooth::BluetoothManager* GetMozBluetooth(ErrorResult& aRv);
-#endif // MOZ_B2G_BT
 #ifdef MOZ_TIME_MANAGER
   time::TimeManager* GetMozTime(ErrorResult& aRv);
 #endif // MOZ_TIME_MANAGER
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   system::AudioChannelManager* GetMozAudioChannelManager(ErrorResult& aRv);
 #endif // MOZ_AUDIO_CHANNEL_MANAGER
 
   Presentation* GetPresentation(ErrorResult& aRv);
@@ -321,19 +312,16 @@ private:
   RefPtr<Promise> mBatteryPromise;
   RefPtr<PowerManager> mPowerManager;
   RefPtr<IccManager> mIccManager;
   RefPtr<InputPortManager> mInputPortManager;
   RefPtr<network::Connection> mConnection;
 #ifdef MOZ_B2G_RIL
   RefPtr<MobileConnectionArray> mMobileConnections;
 #endif
-#ifdef MOZ_B2G_BT
-  RefPtr<bluetooth::BluetoothManager> mBluetooth;
-#endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   RefPtr<system::AudioChannelManager> mAudioChannelManager;
 #endif
   RefPtr<MediaDevices> mMediaDevices;
   nsTArray<nsWeakPtr> mDeviceStorageStores;
   RefPtr<time::TimeManager> mTimeManager;
   RefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
--- a/dom/base/domerr.msg
+++ b/dom/base/domerr.msg
@@ -98,29 +98,16 @@ DOM_MSG_DEF(NS_ERROR_DOM_PROP_ACCESS_DEN
 DOM_MSG_DEF(NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED, "Access to XPConnect service denied")
 DOM_MSG_DEF(NS_ERROR_DOM_BAD_URI, "Access to restricted URI denied")
 DOM_MSG_DEF(NS_ERROR_DOM_RETVAL_UNDEFINED, "Return value is undefined")
 DOM_MSG_DEF(NS_ERROR_DOM_QUOTA_REACHED, "Persistent storage maximum size reached")
 
 DOM4_MSG_DEF(NotFoundError, "File was not found", NS_ERROR_DOM_FILE_NOT_FOUND_ERR)
 DOM4_MSG_DEF(NotReadableError, "File could not be read", NS_ERROR_DOM_FILE_NOT_READABLE_ERR)
 
-/* Non-standard Bluetooth DOM errors. */
-DOM4_MSG_DEF(BtFailError,         "Fail",  NS_ERROR_DOM_BLUETOOTH_FAIL)
-DOM4_MSG_DEF(BtNotReadyError,     "Not ready",  NS_ERROR_DOM_BLUETOOTH_NOT_READY)
-DOM4_MSG_DEF(BtNoMemError,        "No memory",  NS_ERROR_DOM_BLUETOOTH_NOMEM)
-DOM4_MSG_DEF(BtBusyError,         "Device busy with another command",  NS_ERROR_DOM_BLUETOOTH_BUSY)
-DOM4_MSG_DEF(BtDoneError,         "Request already done",  NS_ERROR_DOM_BLUETOOTH_DONE)
-DOM4_MSG_DEF(BtUnsupportedError,  "Unsupported",  NS_ERROR_DOM_BLUETOOTH_UNSUPPORTED)
-DOM4_MSG_DEF(BtParmInvalidError,  "Invalid parameter",  NS_ERROR_DOM_BLUETOOTH_PARM_INVALID)
-DOM4_MSG_DEF(BtUnhandledError,    "Unhandled",  NS_ERROR_DOM_BLUETOOTH_UNHANDLED)
-DOM4_MSG_DEF(BtAuthFailureError,  "Authentication failure",  NS_ERROR_DOM_BLUETOOTH_AUTH_FAILURE)
-DOM4_MSG_DEF(BtRmtDevDownError,   "Remote device down",  NS_ERROR_DOM_BLUETOOTH_RMT_DEV_DOWN)
-DOM4_MSG_DEF(BtAuthRejectedError, "Authentication rejected",  NS_ERROR_DOM_BLUETOOTH_AUTH_REJECTED)
-
 /* Web Animations errors */
 
 DOM4_MSG_DEF(NotSupportedError, "Animation to or from an underlying value is not yet supported.", NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR)
 
 /* common global codes (from nsError.h) */
 
 DOM_MSG_DEF(NS_OK                                  , "Success")
 DOM_MSG_DEF(NS_ERROR_NOT_INITIALIZED               , "Component not initialized")
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -416,18 +416,16 @@ if CONFIG['MOZ_BUILD_APP'] != 'mobile/an
 
 EXTRA_JS_MODULES += [
     'DOMRequestHelper.jsm',
     'IndexedDBHelper.jsm',
 ]
 
 LOCAL_INCLUDES += [
     '../battery',
-    '../bluetooth/common',
-    '../bluetooth/common/webapi',
     '../events',
     '../media',
     '../network',
     '../time',
     '/caps',
     '/docshell/base',
     '/dom/base',
     '/dom/geolocation',
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -102,85 +102,16 @@ DOMInterfaces = {
     'headerFile': 'mozilla/dom/File.h',
 },
 
 'BatteryManager': {
     'nativeType': 'mozilla::dom::battery::BatteryManager',
     'headerFile': 'BatteryManager.h'
 },
 
-'BluetoothAdapter': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothAdapter',
-},
-
-'BluetoothClassOfDevice': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothClassOfDevice',
-},
-
-'BluetoothDevice': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothDevice',
-},
-
-'BluetoothDiscoveryHandle': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothDiscoveryHandle',
-},
-
-'BluetoothGatt': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothGatt',
-},
-
-'BluetoothGattAttributeEvent': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothGattAttributeEvent',
-},
-
-'BluetoothGattCharacteristic': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothGattCharacteristic',
-},
-
-'BluetoothGattDescriptor': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothGattDescriptor',
-},
-
-'BluetoothGattServer': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothGattServer',
-},
-
-'BluetoothGattService': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothGattService',
-},
-
-'BluetoothLeDeviceEvent': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothLeDeviceEvent',
-},
-
-'BluetoothManager': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothManager',
-},
-
-'BluetoothObexAuthHandle': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothObexAuthHandle',
-},
-
-'BluetoothPairingHandle': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothPairingHandle',
-},
-
-'BluetoothPairingListener': {
-    'nativeType':
-      'mozilla::dom::bluetooth::BluetoothPairingListener',
-},
-
-'BluetoothPbapRequestHandle': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothPbapRequestHandle',
-},
-
-'BluetoothMapRequestHandle': {
-    'nativeType': 'mozilla::dom::bluetooth::BluetoothMapRequestHandle',
-},
-
 'BoxObject': {
     'resultNotAddRefed': ['element'],
 },
 
 'Cache': {
     'implicitJSContext': [ 'add', 'addAll' ],
     'nativeType': 'mozilla::dom::cache::Cache',
 },
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -188,17 +188,16 @@ CreateException(JSContext* aCx, nsresult
 {
   // Do we use DOM exceptions for this error code?
   switch (NS_ERROR_GET_MODULE(aRv)) {
   case NS_ERROR_MODULE_DOM:
   case NS_ERROR_MODULE_SVG:
   case NS_ERROR_MODULE_DOM_XPATH:
   case NS_ERROR_MODULE_DOM_INDEXEDDB:
   case NS_ERROR_MODULE_DOM_FILEHANDLE:
-  case NS_ERROR_MODULE_DOM_BLUETOOTH:
   case NS_ERROR_MODULE_DOM_ANIM:
   case NS_ERROR_MODULE_DOM_PUSH:
   case NS_ERROR_MODULE_DOM_MEDIA:
     if (aMessage.IsEmpty()) {
       return DOMException::Create(aRv);
     }
     return DOMException::Create(aRv, aMessage);
   default:
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -54,17 +54,16 @@ EXPORTS.mozilla.dom += [
 # Bug 932082 tracks.
 LOCAL_INCLUDES += [
     '!/dist/include/mozilla/dom',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/battery',
-    '/dom/bluetooth/common/webapi',
     '/dom/canvas',
     '/dom/geolocation',
     '/dom/html',
     '/dom/indexedDB',
     '/dom/media/webaudio',
     '/dom/media/webspeech/recognition',
     '/dom/svg',
     '/dom/workers',
deleted file mode 100644
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ /dev/null
@@ -1,779 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "base/basictypes.h"
-
-#include "BluetoothA2dpManager.h"
-#include "BluetoothCommon.h"
-#include "BluetoothService.h"
-#include "BluetoothSocket.h"
-#include "BluetoothUtils.h"
-
-#include "mozilla/dom/bluetooth/BluetoothTypes.h"
-#include "mozilla/Services.h"
-#include "mozilla/StaticPtr.h"
-#include "MainThreadUtils.h"
-#include "nsIObserverService.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla;
-USING_BLUETOOTH_NAMESPACE
-// AVRC_ID op code follows bluedroid avrc_defs.h
-#define AVRC_ID_REWIND  0x48
-#define AVRC_ID_FAST_FOR 0x49
-#define AVRC_KEY_PRESS_STATE  1
-#define AVRC_KEY_RELEASE_STATE  0
-// bluedroid bt_rc.h
-#define AVRC_MAX_ATTR_STR_LEN 255
-
-namespace {
-  StaticRefPtr<BluetoothA2dpManager> sBluetoothA2dpManager;
-  bool sInShutdown = false;
-  static BluetoothA2dpInterface* sBtA2dpInterface;
-} // namespace
-
-const int BluetoothA2dpManager::MAX_NUM_CLIENTS = 1;
-
-NS_IMETHODIMP
-BluetoothA2dpManager::Observe(nsISupports* aSubject,
-                              const char* aTopic,
-                              const char16_t* aData)
-{
-  MOZ_ASSERT(sBluetoothA2dpManager);
-
-  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
-    HandleShutdown();
-    return NS_OK;
-  }
-
-  MOZ_ASSERT(false, "BluetoothA2dpManager got unexpected topic!");
-  return NS_ERROR_UNEXPECTED;
-}
-
-BluetoothA2dpManager::BluetoothA2dpManager()
-{
-  Reset();
-}
-
-void
-BluetoothA2dpManager::Reset()
-{
-  mA2dpConnected = false;
-  mSinkState = SinkState::SINK_DISCONNECTED;
-  mController = nullptr;
-}
-
-static void
-AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
-{
-  switch (aState) {
-    case A2DP_CONNECTION_STATE_DISCONNECTED:
-      aString.AssignLiteral("disconnected");
-      break;
-    case A2DP_CONNECTION_STATE_CONNECTING:
-      aString.AssignLiteral("connecting");
-      break;
-    case A2DP_CONNECTION_STATE_CONNECTED:
-      aString.AssignLiteral("connected");
-      break;
-    case A2DP_CONNECTION_STATE_DISCONNECTING:
-      aString.AssignLiteral("disconnecting");
-      break;
-    default:
-      BT_WARNING("Unknown sink state %d", static_cast<int>(aState));
-      return;
-  }
-}
-
-class BluetoothA2dpManager::RegisterModuleResultHandler final
-  : public BluetoothSetupResultHandler
-{
-public:
-  RegisterModuleResultHandler(BluetoothA2dpInterface* aInterface,
-                              BluetoothProfileResultHandler* aRes)
-    : mInterface(aInterface)
-    , mRes(aRes)
-  { }
-
-  void OnError(BluetoothStatus aStatus) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    BT_WARNING("BluetoothSetupInterface::RegisterModule failed for A2DP: %d",
-               (int)aStatus);
-
-    mInterface->SetNotificationHandler(nullptr);
-
-    if (mRes) {
-      mRes->OnError(NS_ERROR_FAILURE);
-    }
-  }
-
-  void RegisterModule() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    sBtA2dpInterface = mInterface;
-
-    if (mRes) {
-      mRes->Init();
-    }
-  }
-
-private:
-  BluetoothA2dpInterface* mInterface;
-  RefPtr<BluetoothProfileResultHandler> mRes;
-};
-
-class BluetoothA2dpManager::InitProfileResultHandlerRunnable final
-  : public Runnable
-{
-public:
-  InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
-                                   nsresult aRv)
-    : mRes(aRes)
-    , mRv(aRv)
-  {
-    MOZ_ASSERT(mRes);
-  }
-
-  NS_IMETHOD Run() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (NS_SUCCEEDED(mRv)) {
-      mRes->Init();
-    } else {
-      mRes->OnError(mRv);
-    }
-    return NS_OK;
-  }
-
-private:
-  RefPtr<BluetoothProfileResultHandler> mRes;
-  nsresult mRv;
-};
-
-/*
- * This function will be only called when Bluetooth is turning on.
- * It is important to register a2dp callbacks before enable() gets called.
- * It is required to register a2dp callbacks before a2dp media task
- * starts up.
- */
-// static
-void
-BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (sBtA2dpInterface) {
-    BT_LOGR("Bluetooth A2DP interface is already initalized.");
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_OK);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch A2DP Init runnable");
-    }
-    return;
-  }
-
-  auto btInf = BluetoothInterface::GetInstance();
-
-  if (NS_WARN_IF(!btInf)) {
-    // If there's no Bluetooth interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch A2DP OnError runnable");
-    }
-    return;
-  }
-
-  auto setupInterface = btInf->GetBluetoothSetupInterface();
-
-  if (NS_WARN_IF(!setupInterface)) {
-    // If there's no Setup interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch A2DP OnError runnable");
-    }
-    return;
-  }
-
-  auto a2dpInterface = btInf->GetBluetoothA2dpInterface();
-
-  if (NS_WARN_IF(!a2dpInterface)) {
-    // If there's no A2DP interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch A2DP OnError runnable");
-    }
-    return;
-  }
-
-  // Set notification handler _before_ registering the module. It could
-  // happen that we receive notifications, before the result handler runs.
-  a2dpInterface->SetNotificationHandler(BluetoothA2dpManager::Get());
-
-  setupInterface->RegisterModule(
-    SETUP_SERVICE_ID_A2DP, 0, MAX_NUM_CLIENTS,
-    new RegisterModuleResultHandler(a2dpInterface, aRes));
-}
-
-BluetoothA2dpManager::~BluetoothA2dpManager()
-{ }
-
-void
-BluetoothA2dpManager::Uninit()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE_VOID(obs);
-  if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
-    BT_WARNING("Failed to remove shutdown observer!");
-  }
-}
-
-/*
- * Static functions
- */
-
-static BluetoothA2dpManager::SinkState
-StatusStringToSinkState(const nsAString& aStatus)
-{
-  BluetoothA2dpManager::SinkState state =
-    BluetoothA2dpManager::SinkState::SINK_UNKNOWN;
-  if (aStatus.EqualsLiteral("disconnected")) {
-    state = BluetoothA2dpManager::SinkState::SINK_DISCONNECTED;
-  } else if (aStatus.EqualsLiteral("connecting")) {
-    state = BluetoothA2dpManager::SinkState::SINK_CONNECTING;
-  } else if (aStatus.EqualsLiteral("connected")) {
-    state = BluetoothA2dpManager::SinkState::SINK_CONNECTED;
-  } else if (aStatus.EqualsLiteral("playing")) {
-    state = BluetoothA2dpManager::SinkState::SINK_PLAYING;
-  } else {
-    BT_WARNING("Unknown sink state");
-  }
-  return state;
-}
-
-//static
-BluetoothA2dpManager*
-BluetoothA2dpManager::Get()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // If sBluetoothA2dpManager already exists, exit early
-  if (sBluetoothA2dpManager) {
-    return sBluetoothA2dpManager;
-  }
-
-  // If we're in shutdown, don't create a new instance
-  NS_ENSURE_FALSE(sInShutdown, nullptr);
-
-  // Create a new instance and return
-  sBluetoothA2dpManager = new BluetoothA2dpManager();
-
-  return sBluetoothA2dpManager;
-}
-
-class BluetoothA2dpManager::UnregisterModuleResultHandler final
-  : public BluetoothSetupResultHandler
-{
-public:
-  UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
-    : mRes(aRes)
-  { }
-
-  void OnError(BluetoothStatus aStatus) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for A2DP: %d",
-               (int)aStatus);
-
-    sBtA2dpInterface->SetNotificationHandler(nullptr);
-    sBtA2dpInterface = nullptr;
-
-    sBluetoothA2dpManager->Uninit();
-    sBluetoothA2dpManager = nullptr;
-
-    if (mRes) {
-      mRes->OnError(NS_ERROR_FAILURE);
-    }
-  }
-
-  void UnregisterModule() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    sBtA2dpInterface->SetNotificationHandler(nullptr);
-    sBtA2dpInterface = nullptr;
-
-    sBluetoothA2dpManager->Uninit();
-    sBluetoothA2dpManager = nullptr;
-
-    if (mRes) {
-      mRes->Deinit();
-    }
-  }
-
-private:
-  RefPtr<BluetoothProfileResultHandler> mRes;
-};
-
-class BluetoothA2dpManager::DeinitProfileResultHandlerRunnable final
-  : public Runnable
-{
-public:
-  DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
-                                     nsresult aRv)
-    : mRes(aRes)
-    , mRv(aRv)
-  {
-    MOZ_ASSERT(mRes);
-  }
-
-  NS_IMETHOD Run() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (NS_SUCCEEDED(mRv)) {
-      mRes->Deinit();
-    } else {
-      mRes->OnError(mRv);
-    }
-    return NS_OK;
-  }
-
-private:
-  RefPtr<BluetoothProfileResultHandler> mRes;
-  nsresult mRv;
-};
-
-// static
-void
-BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!sBtA2dpInterface) {
-    BT_LOGR("Bluetooth A2DP interface has not been initalized.");
-    RefPtr<Runnable> r =
-      new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch A2DP Deinit runnable");
-    }
-    return;
-  }
-
-  auto btInf = BluetoothInterface::GetInstance();
-
-  if (NS_WARN_IF(!btInf)) {
-    // If there's no backend interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch A2DP OnError runnable");
-    }
-    return;
-  }
-
-  auto setupInterface = btInf->GetBluetoothSetupInterface();
-
-  if (NS_WARN_IF(!setupInterface)) {
-    // If there's no Setup interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch A2DP OnError runnable");
-    }
-    return;
-  }
-
-  setupInterface->UnregisterModule(
-    SETUP_SERVICE_ID_A2DP,
-    new UnregisterModuleResultHandler(aRes));
-}
-
-void
-BluetoothA2dpManager::HandleShutdown()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  sInShutdown = true;
-  Disconnect(nullptr);
-  sBluetoothA2dpManager = nullptr;
-}
-
-void
-BluetoothA2dpManager::OnConnectError()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  mController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
-
-  mController = nullptr;
-  mDeviceAddress.Clear();
-}
-
-class BluetoothA2dpManager::ConnectResultHandler final
-  : public BluetoothA2dpResultHandler
-{
-public:
-  void OnError(BluetoothStatus aStatus) override
-  {
-    BT_LOGR("BluetoothA2dpInterface::Connect failed: %d", (int)aStatus);
-
-    NS_ENSURE_TRUE_VOID(sBluetoothA2dpManager);
-    sBluetoothA2dpManager->OnConnectError();
-  }
-};
-
-void
-BluetoothA2dpManager::Connect(const BluetoothAddress& aDeviceAddress,
-                              BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!aDeviceAddress.IsCleared());
-  MOZ_ASSERT(aController);
-
-  BluetoothService* bs = BluetoothService::Get();
-  if (!bs || sInShutdown) {
-    aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
-    return;
-  }
-
-  if (mA2dpConnected) {
-    aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED));
-    return;
-  }
-
-  mDeviceAddress = aDeviceAddress;
-  mController = aController;
-
-  if (!sBtA2dpInterface) {
-    BT_LOGR("sBluetoothA2dpInterface is null");
-    aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
-    return;
-  }
-
-  sBtA2dpInterface->Connect(mDeviceAddress, new ConnectResultHandler());
-}
-
-void
-BluetoothA2dpManager::OnDisconnectError()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  NS_ENSURE_TRUE_VOID(mController);
-
-  mController->NotifyCompletion(NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
-}
-
-class BluetoothA2dpManager::DisconnectResultHandler final
-  : public BluetoothA2dpResultHandler
-{
-public:
-  void OnError(BluetoothStatus aStatus) override
-  {
-    BT_LOGR("BluetoothA2dpInterface::Disconnect failed: %d", (int)aStatus);
-
-    NS_ENSURE_TRUE_VOID(sBluetoothA2dpManager);
-    sBluetoothA2dpManager->OnDisconnectError();
-  }
-};
-
-void
-BluetoothA2dpManager::Disconnect(BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mController);
-
-  BluetoothService* bs = BluetoothService::Get();
-  if (!bs) {
-    if (aController) {
-      aController->NotifyCompletion(
-        NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
-    }
-    return;
-  }
-
-  if (!mA2dpConnected) {
-    if (aController) {
-      aController->NotifyCompletion(
-        NS_LITERAL_STRING(ERR_ALREADY_DISCONNECTED));
-    }
-    return;
-  }
-
-  MOZ_ASSERT(!mDeviceAddress.IsCleared());
-
-  mController = aController;
-
-  if (!sBtA2dpInterface) {
-    BT_LOGR("sBluetoothA2dpInterface is null");
-    if (aController) {
-      aController->NotifyCompletion(
-        NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
-    }
-    return;
-  }
-
-  sBtA2dpInterface->Disconnect(mDeviceAddress, new DisconnectResultHandler());
-}
-
-void
-BluetoothA2dpManager::OnConnect(const nsAString& aErrorStr)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  /**
-   * On the one hand, notify the controller that we've done for outbound
-   * connections. On the other hand, we do nothing for inbound connections.
-   */
-  NS_ENSURE_TRUE_VOID(mController);
-
-  RefPtr<BluetoothProfileController> controller = mController.forget();
-  controller->NotifyCompletion(aErrorStr);
-}
-
-void
-BluetoothA2dpManager::OnDisconnect(const nsAString& aErrorStr)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  /**
-   * On the one hand, notify the controller that we've done for outbound
-   * connections. On the other hand, we do nothing for inbound connections.
-   */
-  NS_ENSURE_TRUE_VOID(mController);
-
-  RefPtr<BluetoothProfileController> controller = mController.forget();
-  controller->NotifyCompletion(aErrorStr);
-
-  Reset();
-}
-
-/* HandleSinkPropertyChanged update sink state in A2dp
- *
- * Possible values: "disconnected", "connecting", "connected", "playing"
- *
- * 1. "disconnected" -> "connecting"
- *    Either an incoming or outgoing connection attempt ongoing
- * 2. "connecting" -> "disconnected"
- *    Connection attempt failed
- * 3. "connecting" -> "connected"
- *    Successfully connected
- * 4. "connected" -> "playing"
- *    Audio stream active
- * 5. "playing" -> "connected"
- *    Audio stream suspended
- * 6. "connected" -> "disconnected"
- *    "playing" -> "disconnected"
- *    Disconnected from local or the remote device
- */
-void
-BluetoothA2dpManager::HandleSinkPropertyChanged(const BluetoothSignal& aSignal)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aSignal.value().type() ==
-             BluetoothValue::TArrayOfBluetoothNamedValue);
-
-  BluetoothAddress address;
-  NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(StringToAddress(aSignal.path(), address)));
-
-  /**
-   * Update sink property only if
-   * - mDeviceAddress is empty (A2dp is disconnected), or
-   * - this property change is from the connected sink.
-   */
-  NS_ENSURE_TRUE_VOID(mDeviceAddress.IsCleared() || mDeviceAddress == address);
-
-  const InfallibleTArray<BluetoothNamedValue>& arr =
-    aSignal.value().get_ArrayOfBluetoothNamedValue();
-  MOZ_ASSERT(arr.Length() == 1);
-
-  /**
-   * There are three properties:
-   * - "State": a string
-   * - "Connected": a boolean value
-   * - "Playing": a boolean value
-   *
-   * Note that only "State" is handled in this function.
-   */
-
-  const nsString& name = arr[0].name();
-  NS_ENSURE_TRUE_VOID(name.EqualsLiteral("State"));
-
-  const BluetoothValue& value = arr[0].value();
-  MOZ_ASSERT(value.type() == BluetoothValue::TnsString);
-  SinkState newState = StatusStringToSinkState(value.get_nsString());
-  NS_ENSURE_TRUE_VOID((newState != SinkState::SINK_UNKNOWN) &&
-                      (newState != mSinkState));
-
-  SinkState prevState = mSinkState;
-  mSinkState = newState;
-
-  switch(mSinkState) {
-    case SinkState::SINK_CONNECTING:
-      // case 1: Either an incoming or outgoing connection attempt ongoing
-      MOZ_ASSERT(prevState == SinkState::SINK_DISCONNECTED);
-      break;
-    case SinkState::SINK_PLAYING:
-      // case 4: Audio stream active
-      MOZ_ASSERT(prevState == SinkState::SINK_CONNECTED);
-      break;
-    case SinkState::SINK_CONNECTED:
-      // case 5: Audio stream suspended
-      if (prevState == SinkState::SINK_PLAYING ||
-          prevState == SinkState::SINK_CONNECTED) {
-        break;
-      }
-
-      // case 3: Successfully connected
-      mA2dpConnected = true;
-      mDeviceAddress = address;
-      NotifyConnectionStatusChanged();
-
-      OnConnect(EmptyString());
-      break;
-    case SinkState::SINK_DISCONNECTED:
-      // case 2: Connection attempt failed
-      if (prevState == SinkState::SINK_CONNECTING) {
-        OnConnect(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
-        break;
-      }
-
-      // case 6: Disconnected from the remote device
-      MOZ_ASSERT(prevState == SinkState::SINK_CONNECTED ||
-                 prevState == SinkState::SINK_PLAYING) ;
-
-      mA2dpConnected = false;
-      NotifyConnectionStatusChanged();
-      mDeviceAddress.Clear();
-      OnDisconnect(EmptyString());
-      break;
-    default:
-      break;
-  }
-}
-
-/*
- * Reset connection state to DISCONNECTED to handle backend error. The state
- * change triggers UI status bar update as ordinary bluetooth turn-off sequence.
- */
-void
-BluetoothA2dpManager::HandleBackendError()
-{
-  if (mSinkState != SinkState::SINK_DISCONNECTED) {
-    ConnectionStateNotification(A2DP_CONNECTION_STATE_DISCONNECTED,
-                                mDeviceAddress);
-  }
-}
-
-void
-BluetoothA2dpManager::NotifyConnectionStatusChanged()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Notify Gecko observers
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE_VOID(obs);
-
-  nsAutoString deviceAddressStr;
-  AddressToString(mDeviceAddress, deviceAddressStr);
-
-  if (NS_FAILED(obs->NotifyObservers(this,
-                                     BLUETOOTH_A2DP_STATUS_CHANGED_ID,
-                                     deviceAddressStr.get()))) {
-    BT_WARNING("Failed to notify bluetooth-a2dp-status-changed observsers!");
-  }
-
-  // Dispatch an event of status change
-  DispatchStatusChangedEvent(
-    NS_LITERAL_STRING(A2DP_STATUS_CHANGED_ID), mDeviceAddress, mA2dpConnected);
-}
-
-void
-BluetoothA2dpManager::OnGetServiceChannel(const BluetoothAddress& aDeviceAddress,
-                                          const BluetoothUuid& aServiceUuid,
-                                          int aChannel)
-{
-}
-
-void
-BluetoothA2dpManager::OnUpdateSdpRecords(const BluetoothAddress& aDeviceAddress)
-{
-}
-
-void
-BluetoothA2dpManager::GetAddress(BluetoothAddress& aDeviceAddress)
-{
-  aDeviceAddress = mDeviceAddress;
-}
-
-bool
-BluetoothA2dpManager::IsConnected()
-{
-  return mA2dpConnected;
-}
-
-/*
- * Notifications
- */
-
-void
-BluetoothA2dpManager::ConnectionStateNotification(
-  BluetoothA2dpConnectionState aState, const BluetoothAddress& aBdAddr)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsString a2dpState;
-  AvStatusToSinkString(aState, a2dpState);
-
-  InfallibleTArray<BluetoothNamedValue> props;
-  AppendNamedValue(props, "State", a2dpState);
-
-  nsAutoString addressStr;
-  AddressToString(aBdAddr, addressStr);
-
-  HandleSinkPropertyChanged(BluetoothSignal(NS_LITERAL_STRING("AudioSink"),
-                                            addressStr, props));
-}
-
-void
-BluetoothA2dpManager::AudioStateNotification(BluetoothA2dpAudioState aState,
-                                             const BluetoothAddress& aBdAddr)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsString a2dpState;
-
-  if (aState == A2DP_AUDIO_STATE_STARTED) {
-    a2dpState = NS_LITERAL_STRING("playing");
-  } else if (aState == A2DP_AUDIO_STATE_STOPPED) {
-    // for avdtp state stop stream
-    a2dpState = NS_LITERAL_STRING("connected");
-  } else if (aState == A2DP_AUDIO_STATE_REMOTE_SUSPEND) {
-    // for avdtp state suspend stream from remote side
-    a2dpState = NS_LITERAL_STRING("connected");
-  }
-
-  InfallibleTArray<BluetoothNamedValue> props;
-  AppendNamedValue(props, "State", a2dpState);
-
-  nsAutoString addressStr;
-  AddressToString(aBdAddr, addressStr);
-
-  HandleSinkPropertyChanged(BluetoothSignal(NS_LITERAL_STRING("AudioSink"),
-                                            addressStr, props));
-}
-
-NS_IMPL_ISUPPORTS(BluetoothA2dpManager, nsIObserver)
deleted file mode 100644
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_bluedroid_BluetoothA2dpManager_h
-#define mozilla_dom_bluetooth_bluedroid_BluetoothA2dpManager_h
-
-#include "BluetoothCommon.h"
-#include "BluetoothInterface.h"
-#include "BluetoothProfileController.h"
-#include "BluetoothProfileManagerBase.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-class BluetoothA2dpManager : public BluetoothProfileManagerBase
-                           , public BluetoothA2dpNotificationHandler
-{
-public:
-  static const int MAX_NUM_CLIENTS;
-
-  BT_DECL_PROFILE_MGR_BASE
-  virtual void GetName(nsACString& aName)
-  {
-    aName.AssignLiteral("A2DP");
-  }
-
-  enum SinkState {
-    SINK_UNKNOWN,
-    SINK_DISCONNECTED,
-    SINK_CONNECTING,
-    SINK_CONNECTED,
-    SINK_PLAYING,
-  };
-
-  static BluetoothA2dpManager* Get();
-  static void InitA2dpInterface(BluetoothProfileResultHandler* aRes);
-  static void DeinitA2dpInterface(BluetoothProfileResultHandler* aRes);
-
-  void OnConnectError();
-  void OnDisconnectError();
-
-  // A2DP-specific functions
-  void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);
-
-  void HandleBackendError();
-
-protected:
-  virtual ~BluetoothA2dpManager();
-
-private:
-  class ConnectResultHandler;
-  class DeinitProfileResultHandlerRunnable;
-  class DisconnectResultHandler;
-  class InitProfileResultHandlerRunnable;
-  class RegisterModuleResultHandler;
-  class UnregisterModuleResultHandler;
-
-  BluetoothA2dpManager();
-
-  void Uninit();
-  void HandleShutdown();
-  void NotifyConnectionStatusChanged();
-
-  void ConnectionStateNotification(BluetoothA2dpConnectionState aState,
-                                   const BluetoothAddress& aBdAddr) override;
-  void AudioStateNotification(BluetoothA2dpAudioState aState,
-                              const BluetoothAddress& aBdAddr) override;
-
-  BluetoothAddress mDeviceAddress;
-  RefPtr<BluetoothProfileController> mController;
-
-  // A2DP data member
-  bool mA2dpConnected;
-  SinkState mSinkState;
-};
-
-END_BLUETOOTH_NAMESPACE
-
-#endif
deleted file mode 100644
--- a/dom/bluetooth/bluedroid/BluetoothAvrcpManager.cpp
+++ /dev/null
@@ -1,951 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "base/basictypes.h"
-
-#include "BluetoothAvrcpManager.h"
-#include "BluetoothCommon.h"
-#include "BluetoothService.h"
-#include "BluetoothSocket.h"
-#include "BluetoothUtils.h"
-
-#include "mozilla/dom/bluetooth/BluetoothTypes.h"
-#include "mozilla/Services.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/UniquePtr.h"
-#include "MainThreadUtils.h"
-#include "nsIObserverService.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla;
-USING_BLUETOOTH_NAMESPACE
-// AVRC_ID op code follows bluedroid avrc_defs.h
-#define AVRC_ID_REWIND  0x48
-#define AVRC_ID_FAST_FOR 0x49
-#define AVRC_KEY_PRESS_STATE  1
-#define AVRC_KEY_RELEASE_STATE  0
-// bluedroid bt_rc.h
-#define AVRC_MAX_ATTR_STR_LEN 255
-
-namespace {
-  StaticRefPtr<BluetoothAvrcpManager> sBluetoothAvrcpManager;
-  bool sInShutdown = false;
-  static BluetoothAvrcpInterface* sBtAvrcpInterface;
-} // namespace
-
-const int BluetoothAvrcpManager::MAX_NUM_CLIENTS = 1;
-
-/*
- * This function maps attribute id and returns corresponding values
- */
-static void
-ConvertAttributeString(BluetoothAvrcpMediaAttribute aAttrId,
-                       nsAString& aAttrStr)
-{
-  BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
-  NS_ENSURE_TRUE_VOID(avrcp);
-
-  switch (aAttrId) {
-    case AVRCP_MEDIA_ATTRIBUTE_TITLE:
-      avrcp->GetTitle(aAttrStr);
-      /*
-       * bluedroid can only send string length AVRC_MAX_ATTR_STR_LEN - 1
-       */
-      if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
-        aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
-        BT_WARNING("Truncate media item attribute title, length is over 255");
-      }
-      break;
-    case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
-      avrcp->GetArtist(aAttrStr);
-      if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
-        aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
-        BT_WARNING("Truncate media item attribute artist, length is over 255");
-      }
-      break;
-    case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
-      avrcp->GetAlbum(aAttrStr);
-      if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
-        aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
-        BT_WARNING("Truncate media item attribute album, length is over 255");
-      }
-      break;
-    case AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM:
-      aAttrStr.AppendInt(avrcp->GetMediaNumber());
-      break;
-    case AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS:
-      aAttrStr.AppendInt(avrcp->GetTotalMediaNumber());
-      break;
-    case AVRCP_MEDIA_ATTRIBUTE_GENRE:
-      // TODO: we currently don't support genre from music player
-      aAttrStr.Truncate();
-      break;
-    case AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME:
-      aAttrStr.AppendInt(avrcp->GetDuration());
-      break;
-  }
-}
-
-NS_IMETHODIMP
-BluetoothAvrcpManager::Observe(nsISupports* aSubject,
-                               const char* aTopic,
-                               const char16_t* aData)
-{
-  MOZ_ASSERT(sBluetoothAvrcpManager);
-
-  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
-    HandleShutdown();
-    return NS_OK;
-  }
-
-  MOZ_ASSERT(false, "BluetoothAvrcpManager got unexpected topic!");
-  return NS_ERROR_UNEXPECTED;
-}
-
-BluetoothAvrcpManager::BluetoothAvrcpManager()
-{
-  Reset();
-}
-
-void
-BluetoothAvrcpManager::Reset()
-{
-  mAvrcpConnected = false;
-  mDuration = 0;
-  mMediaNumber = 0;
-  mTotalMediaCount = 0;
-  mPosition = 0;
-  mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
-}
-
-class BluetoothAvrcpManager::RegisterModuleResultHandler final
-  : public BluetoothSetupResultHandler
-{
-public:
-  RegisterModuleResultHandler(BluetoothAvrcpInterface* aInterface,
-                              BluetoothProfileResultHandler* aRes)
-    : mInterface(aInterface)
-    , mRes(aRes)
-  {
-    MOZ_ASSERT(mInterface);
-  }
-
-  void OnError(BluetoothStatus aStatus) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    BT_WARNING("BluetoothSetupInterface::RegisterModule failed for AVRCP: %d",
-               (int)aStatus);
-
-    mInterface->SetNotificationHandler(nullptr);
-
-    if (mRes) {
-      if (aStatus == STATUS_UNSUPPORTED) {
-        /* Not all versions of Bluedroid support AVRCP. So if the
-         * initialization fails with STATUS_UNSUPPORTED, we still
-         * signal success.
-         */
-        mRes->Init();
-      } else {
-        mRes->OnError(NS_ERROR_FAILURE);
-      }
-    }
-  }
-
-  void RegisterModule() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    sBtAvrcpInterface = mInterface;
-
-    if (mRes) {
-      mRes->Init();
-    }
-  }
-
-private:
-  BluetoothAvrcpInterface* mInterface;
-  RefPtr<BluetoothProfileResultHandler> mRes;
-};
-
-class BluetoothAvrcpManager::InitProfileResultHandlerRunnable final
-  : public Runnable
-{
-public:
-  InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
-                                   nsresult aRv)
-    : mRes(aRes)
-    , mRv(aRv)
-  {
-    MOZ_ASSERT(mRes);
-  }
-
-  NS_IMETHOD Run() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (NS_SUCCEEDED(mRv)) {
-      mRes->Init();
-    } else {
-      mRes->OnError(mRv);
-    }
-    return NS_OK;
-  }
-
-private:
-  RefPtr<BluetoothProfileResultHandler> mRes;
-  nsresult mRv;
-};
-
-/*
- * This function will be only called when Bluetooth is turning on.
- */
-// static
-void
-BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (sBtAvrcpInterface) {
-    BT_LOGR("Bluetooth AVRCP interface is already initalized.");
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_OK);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch AVRCP Init runnable");
-    }
-    return;
-  }
-
-  auto btInf = BluetoothInterface::GetInstance();
-
-  if (NS_WARN_IF(!btInf)) {
-    // If there's no Bluetooth interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch AVRCP OnError runnable");
-    }
-    return;
-  }
-
-  auto setupInterface = btInf->GetBluetoothSetupInterface();
-
-  if (NS_WARN_IF(!setupInterface)) {
-    // If there's no Setup interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch AVRCP OnError runnable");
-    }
-    return;
-  }
-
-  auto avrcpInterface = btInf->GetBluetoothAvrcpInterface();
-
-  if (NS_WARN_IF(!avrcpInterface)) {
-    // If there's no AVRCP interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch AVRCP OnError runnable");
-    }
-    return;
-  }
-
-  // Set notification handler _before_ registering the module. It could
-  // happen that we receive notifications, before the result handler runs.
-  avrcpInterface->SetNotificationHandler(BluetoothAvrcpManager::Get());
-
-  setupInterface->RegisterModule(
-    SETUP_SERVICE_ID_AVRCP, 0, MAX_NUM_CLIENTS,
-    new RegisterModuleResultHandler(avrcpInterface, aRes));
-}
-
-BluetoothAvrcpManager::~BluetoothAvrcpManager()
-{ }
-
-void
-BluetoothAvrcpManager::Uninit()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE_VOID(obs);
-  if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
-    BT_WARNING("Failed to remove shutdown observer!");
-  }
-}
-
-/*
- * Static functions
- */
-
-//static
-BluetoothAvrcpManager*
-BluetoothAvrcpManager::Get()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // If sBluetoothAvrcpManager already exists, exit early
-  if (sBluetoothAvrcpManager) {
-    return sBluetoothAvrcpManager;
-  }
-
-  // If we're in shutdown, don't create a new instance
-  NS_ENSURE_FALSE(sInShutdown, nullptr);
-
-  // Create a new instance and return
-  sBluetoothAvrcpManager = new BluetoothAvrcpManager();
-
-  return sBluetoothAvrcpManager;
-}
-
-class BluetoothAvrcpManager::UnregisterModuleResultHandler final
-  : public BluetoothSetupResultHandler
-{
-public:
-  UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
-    : mRes(aRes)
-  { }
-
-  void OnError(BluetoothStatus aStatus) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for AVRCP: %d",
-               (int)aStatus);
-
-    sBtAvrcpInterface->SetNotificationHandler(nullptr);
-    sBtAvrcpInterface = nullptr;
-
-    sBluetoothAvrcpManager->Uninit();
-    sBluetoothAvrcpManager = nullptr;
-
-    if (mRes) {
-      mRes->OnError(NS_ERROR_FAILURE);
-    }
-  }
-
-  void UnregisterModule() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    sBtAvrcpInterface->SetNotificationHandler(nullptr);
-    sBtAvrcpInterface = nullptr;
-
-    sBluetoothAvrcpManager->Uninit();
-    sBluetoothAvrcpManager = nullptr;
-
-    if (mRes) {
-      mRes->Deinit();
-    }
-  }
-
-private:
-  RefPtr<BluetoothProfileResultHandler> mRes;
-};
-
-class BluetoothAvrcpManager::DeinitProfileResultHandlerRunnable final
-  : public Runnable
-{
-public:
-  DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
-                                     nsresult aRv)
-    : mRes(aRes)
-    , mRv(aRv)
-  {
-    MOZ_ASSERT(mRes);
-  }
-
-  NS_IMETHOD Run() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (NS_SUCCEEDED(mRv)) {
-      mRes->Deinit();
-    } else {
-      mRes->OnError(mRv);
-    }
-    return NS_OK;
-  }
-
-private:
-  RefPtr<BluetoothProfileResultHandler> mRes;
-  nsresult mRv;
-};
-
-// static
-void
-BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!sBtAvrcpInterface) {
-    BT_LOGR("Bluetooth AVRCP interface has not been initalized.");
-    RefPtr<Runnable> r =
-      new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch AVRCP Deinit runnable");
-    }
-    return;
-  }
-
-  auto btInf = BluetoothInterface::GetInstance();
-
-  if (NS_WARN_IF(!btInf)) {
-    // If there's no backend interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch AVRCP OnError runnable");
-    }
-    return;
-  }
-
-  auto setupInterface = btInf->GetBluetoothSetupInterface();
-
-  if (NS_WARN_IF(!setupInterface)) {
-    // If there's no Setup interface, we dispatch a runnable
-    // that calls the profile result handler.
-    RefPtr<Runnable> r =
-      new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
-    if (NS_FAILED(NS_DispatchToMainThread(r))) {
-      BT_LOGR("Failed to dispatch AVRCP OnError runnable");
-    }
-    return;
-  }
-
-  setupInterface->UnregisterModule(
-    SETUP_SERVICE_ID_AVRCP,
-    new UnregisterModuleResultHandler(aRes));
-}
-
-void
-BluetoothAvrcpManager::HandleShutdown()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  sInShutdown = true;
-  Disconnect(nullptr);
-  sBluetoothAvrcpManager = nullptr;
-}
-
-class BluetoothAvrcpManager::ConnectRunnable final : public Runnable
-{
-public:
-  ConnectRunnable(BluetoothAvrcpManager* aManager)
-    : mManager(aManager)
-  {
-    MOZ_ASSERT(mManager);
-  }
-  NS_IMETHOD Run() override
-  {
-    mManager->OnConnect(EmptyString());
-    return NS_OK;
-  }
-private:
-  BluetoothAvrcpManager* mManager;
-};
-
-void
-BluetoothAvrcpManager::Connect(const BluetoothAddress& aDeviceAddress,
-                               BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!aDeviceAddress.IsCleared());
-  MOZ_ASSERT(aController);
-
-  // AVRCP doesn't require connecting. We just set the remote address here.
-  mDeviceAddress = aDeviceAddress;
-  mController = aController;
-  SetConnected(true);
-
-  NS_DispatchToMainThread(new ConnectRunnable(this));
-}
-
-class BluetoothAvrcpManager::DisconnectRunnable final : public Runnable
-{
-public:
-  DisconnectRunnable(BluetoothAvrcpManager* aManager)
-    : mManager(aManager)
-  {
-    MOZ_ASSERT(mManager);
-  }
-  NS_IMETHOD Run() override
-  {
-    mManager->OnDisconnect(EmptyString());
-    return NS_OK;
-  }
-private:
-  BluetoothAvrcpManager* mManager;
-};
-
-void
-BluetoothAvrcpManager::Disconnect(BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mController);
-
-  mDeviceAddress.Clear();
-  mController = aController;
-  SetConnected(false);
-
-  NS_DispatchToMainThread(new DisconnectRunnable(this));
-}
-
-void
-BluetoothAvrcpManager::OnConnect(const nsAString& aErrorStr)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  /**
-   * On the one hand, notify the controller that we've done for outbound
-   * connections. On the other hand, we do nothing for inbound connections.
-   */
-  NS_ENSURE_TRUE_VOID(mController);
-
-  RefPtr<BluetoothProfileController> controller = mController.forget();
-  controller->NotifyCompletion(aErrorStr);
-}
-
-void
-BluetoothAvrcpManager::OnDisconnect(const nsAString& aErrorStr)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  /**
-   * On the one hand, notify the controller that we've done for outbound
-   * connections. On the other hand, we do nothing for inbound connections.
-   */
-  NS_ENSURE_TRUE_VOID(mController);
-
-  RefPtr<BluetoothProfileController> controller = mController.forget();
-  controller->NotifyCompletion(aErrorStr);
-
-  Reset();
-}
-
-void
-BluetoothAvrcpManager::OnGetServiceChannel(
-  const BluetoothAddress& aDeviceAddress,
-  const BluetoothUuid& aServiceUuid,
-  int aChannel)
-{ }
-
-void
-BluetoothAvrcpManager::OnUpdateSdpRecords(
-  const BluetoothAddress& aDeviceAddress)
-{ }
-
-void
-BluetoothAvrcpManager::GetAddress(BluetoothAddress& aDeviceAddress)
-{
-  aDeviceAddress = mDeviceAddress;
-}
-
-bool
-BluetoothAvrcpManager::IsConnected()
-{
-  return mAvrcpConnected;
-}
-
-/*
- * In bluedroid stack case, there is no interface to know exactly
- * avrcp connection status. All connection are managed by bluedroid stack.
- */
-void
-BluetoothAvrcpManager::SetConnected(bool aConnected)
-{
-  mAvrcpConnected = aConnected;
-  if (!aConnected) {
-    Reset();
-  }
-}
-
-/*
- * This function only updates meta data in BluetoothAvrcpManager. Send
- * "Get Element Attributes response" in AvrcpGetElementAttrCallback
- */
-void
-BluetoothAvrcpManager::UpdateMetaData(const nsAString& aTitle,
-                                      const nsAString& aArtist,
-                                      const nsAString& aAlbum,
-                                      uint64_t aMediaNumber,
-                                      uint64_t aTotalMediaCount,
-                                      uint32_t aDuration)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
-
-  // Send track changed and position changed if track num is not the same.
-  // See also AVRCP 1.3 Spec 5.4.2
-  if (mMediaNumber != aMediaNumber &&
-      mTrackChangedNotifyType == AVRCP_NTF_INTERIM) {
-    BluetoothAvrcpNotificationParam param;
-    // convert to network big endian format
-    // since track stores as uint8[8]
-    // 56 = 8 * (AVRCP_UID_SIZE -1)
-    for (int i = 0; i < AVRCP_UID_SIZE; ++i) {
-      param.mTrack[i] = (aMediaNumber >> (56 - 8 * i));
-    }
-    mTrackChangedNotifyType = AVRCP_NTF_CHANGED;
-    sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_TRACK_CHANGE,
-                                               AVRCP_NTF_CHANGED,
-                                               param, nullptr);
-    if (mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
-      param.mSongPos = mPosition;
-      // EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
-      mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
-      sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
-                                                 AVRCP_NTF_CHANGED,
-                                                 param, nullptr);
-    }
-  }
-
-  mTitle.Assign(aTitle);
-  mArtist.Assign(aArtist);
-  mAlbum.Assign(aAlbum);
-  mMediaNumber = aMediaNumber;
-  mTotalMediaCount = aTotalMediaCount;
-  mDuration = aDuration;
-}
-
-/*
- * This function is to reply AvrcpGetPlayStatusCallback (play-status-request)
- * from media player application (Gaia side)
- */
-void
-BluetoothAvrcpManager::UpdatePlayStatus(uint32_t aDuration,
-                                        uint32_t aPosition,
-                                        ControlPlayStatus aPlayStatus)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
-  // always update playstatus first
-  sBtAvrcpInterface->GetPlayStatusRsp(aPlayStatus, aDuration,
-                                      aPosition, nullptr);
-  // when play status changed, send both play status and position
-  if (mPlayStatus != aPlayStatus &&
-      mPlayStatusChangedNotifyType == AVRCP_NTF_INTERIM) {
-    BluetoothAvrcpNotificationParam param;
-    param.mPlayStatus = aPlayStatus;
-    mPlayStatusChangedNotifyType = AVRCP_NTF_CHANGED;
-    sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_STATUS_CHANGED,
-                                               AVRCP_NTF_CHANGED,
-                                               param, nullptr);
-  }
-
-  if (mPosition != aPosition &&
-      mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
-    BluetoothAvrcpNotificationParam param;
-    param.mSongPos = aPosition;
-    mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
-    sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
-                                               AVRCP_NTF_CHANGED,
-                                               param, nullptr);
-  }
-
-  mDuration = aDuration;
-  mPosition = aPosition;
-  mPlayStatus = aPlayStatus;
-}
-
-/*
- * This function handles RegisterNotification request from
- * AvrcpRegisterNotificationCallback, which updates current
- * track/status/position status in the INTERRIM response.
- *
- * aParam is only valid when position changed
- */
-void
-BluetoothAvrcpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
-                                                  uint32_t aParam)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
-
-  BluetoothAvrcpNotificationParam param;
-
-  switch (aEvent) {
-    case AVRCP_EVENT_PLAY_STATUS_CHANGED:
-      mPlayStatusChangedNotifyType = AVRCP_NTF_INTERIM;
-      param.mPlayStatus = mPlayStatus;
-      break;
-    case AVRCP_EVENT_TRACK_CHANGE:
-      // In AVRCP 1.3 and 1.4, the identifier parameter of EVENT_TRACK_CHANGED
-      // is different.
-      // AVRCP 1.4: If no track is selected, we shall return 0xFFFFFFFFFFFFFFFF,
-      // otherwise return 0x0 in the INTERRIM response. The expanded text in
-      // version 1.4 is to allow for new UID feature. As for AVRCP 1.3, we shall
-      // return 0xFFFFFFFF. Since PTS enforces to check this part to comply with
-      // the most updated spec.
-      mTrackChangedNotifyType = AVRCP_NTF_INTERIM;
-      // needs to convert to network big endian format since track stores
-      // as uint8[8]. 56 = 8 * (BTRC_UID_SIZE -1).
-      for (int index = 0; index < AVRCP_UID_SIZE; ++index) {
-        // We cannot easily check if a track is selected, so whenever A2DP is
-        // streaming, we assume a track is selected.
-        if (mPlayStatus == ControlPlayStatus::PLAYSTATUS_PLAYING) {
-          param.mTrack[index] = 0x0;
-        } else {
-          param.mTrack[index] = 0xFF;
-        }
-      }
-      break;
-    case AVRCP_EVENT_PLAY_POS_CHANGED:
-      // If no track is selected, return 0xFFFFFFFF in the INTERIM response
-      mPlayPosChangedNotifyType = AVRCP_NTF_INTERIM;
-      if (mPlayStatus == ControlPlayStatus::PLAYSTATUS_PLAYING) {
-        param.mSongPos = mPosition;
-      } else {
-        param.mSongPos = 0xFFFFFFFF;
-      }
-      mPlaybackInterval = aParam;
-      break;
-    case AVRCP_EVENT_APP_SETTINGS_CHANGED:
-      mAppSettingsChangedNotifyType = AVRCP_NTF_INTERIM;
-      param.mNumAttr = 2;
-      param.mIds[0] = AVRCP_PLAYER_ATTRIBUTE_REPEAT;
-      param.mValues[0] = AVRCP_PLAYER_VAL_OFF_REPEAT;
-      param.mIds[1] = AVRCP_PLAYER_ATTRIBUTE_SHUFFLE;
-      param.mValues[1] = AVRCP_PLAYER_VAL_OFF_SHUFFLE;
-      break;
-    default:
-      break;
-  }
-
-  sBtAvrcpInterface->RegisterNotificationRsp(aEvent, AVRCP_NTF_INTERIM,
-                                             param, nullptr);
-}
-
-void
-BluetoothAvrcpManager::GetAlbum(nsAString& aAlbum)
-{
-  aAlbum.Assign(mAlbum);
-}
-
-uint32_t
-BluetoothAvrcpManager::GetDuration()
-{
-  return mDuration;
-}
-
-ControlPlayStatus
-BluetoothAvrcpManager::GetPlayStatus()
-{
-  return mPlayStatus;
-}
-
-uint32_t
-BluetoothAvrcpManager::GetPosition()
-{
-  return mPosition;
-}
-
-uint64_t
-BluetoothAvrcpManager::GetMediaNumber()
-{
-  return mMediaNumber;
-}
-
-uint64_t
-BluetoothAvrcpManager::GetTotalMediaNumber()
-{
-  return mTotalMediaCount;
-}
-
-void
-BluetoothAvrcpManager::GetTitle(nsAString& aTitle)
-{
-  aTitle.Assign(mTitle);
-}
-
-void
-BluetoothAvrcpManager::GetArtist(nsAString& aArtist)
-{
-  aArtist.Assign(mArtist);
-}
-
-/*
- * Notifications
- */
-
-void
-BluetoothAvrcpManager::GetPlayStatusNotification()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  BluetoothService* bs = BluetoothService::Get();
-  if (!bs) {
-    return;
-  }
-
-  bs->DistributeSignal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
-                       NS_LITERAL_STRING(KEY_ADAPTER));
-}
-
-/* Player application settings is optional for AVRCP 1.3. B2G
- * currently does not support player-application-setting related
- * functionality.
- */
-void
-BluetoothAvrcpManager::ListPlayerAppAttrNotification()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP application-setting-related functions
-}
-
-void
-BluetoothAvrcpManager::ListPlayerAppValuesNotification(
-  BluetoothAvrcpPlayerAttribute aAttrId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP application-setting-related functions
-}
-
-void
-BluetoothAvrcpManager::GetPlayerAppValueNotification(
-  uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP application-setting-related functions
-}
-
-void
-BluetoothAvrcpManager::GetPlayerAppAttrsTextNotification(
-  uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP application-setting-related functions
-}
-
-void
-BluetoothAvrcpManager::GetPlayerAppValuesTextNotification(
-  uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP application-setting-related functions
-}
-
-void
-BluetoothAvrcpManager::SetPlayerAppValueNotification(
-  const BluetoothAvrcpPlayerSettings& aSettings)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP application-setting-related functions
-}
-
-/* This method returns element attributes, which are requested from
- * CT. Unlike BlueZ it calls only UpdateMetaData. Bluedroid does not cache
- * meta-data information, but instead uses |GetElementAttrNotifications|
- * and |GetElementAttrRsp| request them.
- */
-void
-BluetoothAvrcpManager::GetElementAttrNotification(
-  uint8_t aNumAttrs, const BluetoothAvrcpMediaAttribute* aAttrs)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  auto attrs = MakeUnique<BluetoothAvrcpElementAttribute[]>(aNumAttrs);
-
-  for (uint8_t i = 0; i < aNumAttrs; ++i) {
-    attrs[i].mId = aAttrs[i];
-    ConvertAttributeString(
-      static_cast<BluetoothAvrcpMediaAttribute>(attrs[i].mId),
-      attrs[i].mValue);
-  }
-
-  MOZ_ASSERT(sBtAvrcpInterface);
-  sBtAvrcpInterface->GetElementAttrRsp(aNumAttrs, attrs.get(), nullptr);
-}
-
-void
-BluetoothAvrcpManager::RegisterNotificationNotification(
-  BluetoothAvrcpEvent aEvent, uint32_t aParam)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
-  if (!avrcp) {
-    return;
-  }
-
-  avrcp->UpdateRegisterNotification(aEvent, aParam);
-}
-
-/* This method is used to get CT features from the Feature Bit Mask. If
- * Advanced Control Player bit is set, the CT supports volume sync (absolute
- * volume feature). If Browsing bit is set, AVRCP 1.4 Browse feature will be
- * supported.
- */
-void
-BluetoothAvrcpManager::RemoteFeatureNotification(
-  const BluetoothAddress& aBdAddr, unsigned long aFeatures)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP 1.4 absolute volume/browse
-}
-
-/* This method is used to get notifications about volume changes on the
- * remote car kit (if it supports AVRCP 1.4), not notification from phone.
- */
-void
-BluetoothAvrcpManager::VolumeChangeNotification(uint8_t aVolume,
-                                                uint8_t aCType)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // TODO: Support AVRCP 1.4 absolute volume/browse
-}
-
-void
-BluetoothAvrcpManager::PassthroughCmdNotification(uint8_t aId,
-                                                  uint8_t aKeyState)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Fast-forward and rewind key events won't be generated from bluedroid
-  // stack after ANDROID_VERSION > 18, but via passthrough callback.
-  nsAutoString name;
-  NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
-                      aKeyState == AVRC_KEY_RELEASE_STATE);
-  switch (aId) {
-    case AVRC_ID_FAST_FOR:
-      if (aKeyState == AVRC_KEY_PRESS_STATE) {
-        name.AssignLiteral("media-fast-forward-button-press");
-      } else {
-        name.AssignLiteral("media-fast-forward-button-release");
-      }
-      break;
-    case AVRC_ID_REWIND:
-      if (aKeyState == AVRC_KEY_PRESS_STATE) {
-        name.AssignLiteral("media-rewind-button-press");
-      } else {
-        name.AssignLiteral("media-rewind-button-release");
-      }
-      break;
-    default:
-      BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
-      return;
-  }
-
-  NS_NAMED_LITERAL_STRING(type, "media-button");
-  BroadcastSystemMessage(type, BluetoothValue(name));
-}
-
-NS_IMPL_ISUPPORTS(BluetoothAvrcpManager, nsIObserver)
-
deleted file mode 100644
--- a/dom/bluetooth/bluedroid/BluetoothAvrcpManager.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
-#define mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
-
-#include "BluetoothCommon.h"
-#include "BluetoothInterface.h"
-#include "BluetoothProfileController.h"
-#include "BluetoothProfileManagerBase.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-class BluetoothAvrcpManager : public BluetoothProfileManagerBase
-                            , public BluetoothAvrcpNotificationHandler
-{
-public:
-  static const int MAX_NUM_CLIENTS;
-
-  BT_DECL_PROFILE_MGR_BASE
-  virtual void GetName(nsACString& aName)
-  {
-    aName.AssignLiteral("AVRCP");
-  }
-
-  enum SinkState {
-    SINK_UNKNOWN,
-    SINK_DISCONNECTED,
-    SINK_CONNECTING,
-    SINK_CONNECTED,
-    SINK_PLAYING,
-  };
-
-  static BluetoothAvrcpManager* Get();
-  static void InitAvrcpInterface(BluetoothProfileResultHandler* aRes);
-  static void DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes);
-
-  void SetConnected(bool aConnected);
-  void UpdateMetaData(const nsAString& aTitle,
-                      const nsAString& aArtist,
-                      const nsAString& aAlbum,
-                      uint64_t aMediaNumber,
-                      uint64_t aTotalMediaCount,
-                      uint32_t aDuration);
-  void UpdatePlayStatus(uint32_t aDuration,
-                        uint32_t aPosition,
-                        ControlPlayStatus aPlayStatus);
-  void UpdateRegisterNotification(BluetoothAvrcpEvent aEvent, uint32_t aParam);
-  void GetAlbum(nsAString& aAlbum);
-  uint32_t GetDuration();
-  ControlPlayStatus GetPlayStatus();
-  uint32_t GetPosition();
-  uint64_t GetMediaNumber();
-  uint64_t GetTotalMediaNumber();
-  void GetTitle(nsAString& aTitle);
-  void GetArtist(nsAString& aArtist);
-  void HandleBackendError();
-
-protected:
-  virtual ~BluetoothAvrcpManager();
-
-private:
-  class ConnectRunnable;
-  class DeinitProfileResultHandlerRunnable;
-  class DisconnectRunnable;
-  class InitProfileResultHandlerRunnable;
-  class RegisterModuleResultHandler;
-  class UnregisterModuleResultHandler;
-
-  BluetoothAvrcpManager();
-
-  void Uninit();
-  void HandleShutdown();
-  void NotifyConnectionStatusChanged();
-
-  void GetPlayStatusNotification() override;
-
-  void ListPlayerAppAttrNotification() override;
-
-  void ListPlayerAppValuesNotification(
-    BluetoothAvrcpPlayerAttribute aAttrId) override;
-
-  void GetPlayerAppValueNotification(
-    uint8_t aNumAttrs,
-    const BluetoothAvrcpPlayerAttribute* aAttrs) override;
-
-  void GetPlayerAppAttrsTextNotification(
-    uint8_t aNumAttrs,
-    const BluetoothAvrcpPlayerAttribute* aAttrs) override;
-
-  void GetPlayerAppValuesTextNotification(
-    uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues) override;
-
-  void SetPlayerAppValueNotification(
-    const BluetoothAvrcpPlayerSettings& aSettings) override;
-
-  void GetElementAttrNotification(
-    uint8_t aNumAttrs,
-    const BluetoothAvrcpMediaAttribute* aAttrs) override;
-
-  void RegisterNotificationNotification(
-    BluetoothAvrcpEvent aEvent, uint32_t aParam) override;
-
-  void RemoteFeatureNotification(
-    const BluetoothAddress& aBdAddr, unsigned long aFeatures) override;
-
-  void VolumeChangeNotification(uint8_t aVolume, uint8_t aCType) override;
-
-  void PassthroughCmdNotification(uint8_t aId, uint8_t aKeyState) override;
-
-  BluetoothAddress mDeviceAddress;
-  RefPtr<BluetoothProfileController> mController;
-
-  bool mAvrcpConnected;
-  nsString mAlbum;
-  nsString mArtist;
-  nsString mTitle;
-  uint32_t mDuration;
-  uint64_t mMediaNumber;
-  uint64_t mTotalMediaCount;
-  uint32_t mPosition;
-  /*
-   * mPlaybackInterval specifies the time interval (in seconds) at which
-   * the change in playback position will be notified. If the song is being
-   * forwarded / rewound, a notification will be received whenever the playback
-   * position will change by this value.
-   */
-  uint32_t mPlaybackInterval;
-  ControlPlayStatus mPlayStatus;
-  /*
-   * Notification types: 1. INTERIM 2. CHANGED
-   * 1. The initial response to this Notify command shall be an INTERIM
-   * response with current status.
-   * 2. The following response shall be a CHANGED response with the updated
-   * status.
-   * mPlayStatusChangedNotifType, mTrackChangedNotifType,
-   * mPlayPosChangedNotifType represents current RegisterNotification
-   * notification type.
-   */
-  BluetoothAvrcpNotification mPlayStatusChangedNotifyType;
-  BluetoothAvrcpNotification mTrackChangedNotifyType;
-  BluetoothAvrcpNotification mPlayPosChangedNotifyType;
-  BluetoothAvrcpNotification mAppSettingsChangedNotifyType;
-};
-
-END_BLUETOOTH_NAMESPACE
-
-#endif // mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
deleted file mode 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "BluetoothDaemonA2dpInterface.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/Unused.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-using namespace mozilla::ipc;
-
-//
-// A2DP module
-//
-
-BluetoothA2dpNotificationHandler*
-  BluetoothDaemonA2dpModule::sNotificationHandler;
-
-void
-BluetoothDaemonA2dpModule::SetNotificationHandler(
-  BluetoothA2dpNotificationHandler* aNotificationHandler)
-{
-  sNotificationHandler = aNotificationHandler;
-}
-
-void
-BluetoothDaemonA2dpModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
-                                     DaemonSocketPDU& aPDU,
-                                     DaemonSocketResultHandler* aRes)
-{
-  static void (BluetoothDaemonA2dpModule::* const HandleOp[])(
-    const DaemonSocketPDUHeader&, DaemonSocketPDU&,
-    DaemonSocketResultHandler*) = {
-    [0] = &BluetoothDaemonA2dpModule::HandleRsp,
-    [1] = &BluetoothDaemonA2dpModule::HandleNtf
-  };
-
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  // negate twice to map bit to 0/1
-  unsigned int isNtf = !!(aHeader.mOpcode & 0x80);
-
-  (this->*(HandleOp[isNtf]))(aHeader, aPDU, aRes);
-}
-
-// Commands
-//
-
-nsresult
-BluetoothDaemonA2dpModule::ConnectCmd(
-  const BluetoothAddress& aRemoteAddr, BluetoothA2dpResultHandler* aRes)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  UniquePtr<DaemonSocketPDU> pdu =
-    MakeUnique<DaemonSocketPDU>(SERVICE_ID, OPCODE_CONNECT,
-                                6); // Address
-
-  nsresult rv = PackPDU(aRemoteAddr, *pdu);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  rv = Send(pdu.get(), aRes);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  Unused << pdu.release();
-  return NS_OK;
-}
-
-nsresult
-BluetoothDaemonA2dpModule::DisconnectCmd(
-  const BluetoothAddress& aRemoteAddr, BluetoothA2dpResultHandler* aRes)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  UniquePtr<DaemonSocketPDU> pdu =
-    MakeUnique<DaemonSocketPDU>(SERVICE_ID, OPCODE_DISCONNECT,
-                                6); // Address
-
-  nsresult rv = PackPDU(aRemoteAddr, *pdu);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  rv = Send(pdu.get(), aRes);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  Unused << pdu.release();
-  return NS_OK;
-}
-
-// Responses
-//
-
-void
-BluetoothDaemonA2dpModule::ErrorRsp(
-  const DaemonSocketPDUHeader& aHeader,
-  DaemonSocketPDU& aPDU, BluetoothA2dpResultHandler* aRes)
-{
-  ErrorRunnable::Dispatch(
-    aRes, &BluetoothA2dpResultHandler::OnError, UnpackPDUInitOp(aPDU));
-}
-
-void
-BluetoothDaemonA2dpModule::ConnectRsp(
-  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
-  BluetoothA2dpResultHandler* aRes)
-{
-  ResultRunnable::Dispatch(
-    aRes, &BluetoothA2dpResultHandler::Connect, UnpackPDUInitOp(aPDU));
-}
-
-void
-BluetoothDaemonA2dpModule::DisconnectRsp(
-  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
-  BluetoothA2dpResultHandler* aRes)
-{
-  ResultRunnable::Dispatch(
-    aRes, &BluetoothA2dpResultHandler::Disconnect, UnpackPDUInitOp(aPDU));
-}
-
-void
-BluetoothDaemonA2dpModule::HandleRsp(
-  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
-  DaemonSocketResultHandler* aRes)
-{
-  static void (BluetoothDaemonA2dpModule::* const HandleRsp[])(
-    const DaemonSocketPDUHeader&,
-    DaemonSocketPDU&,
-    BluetoothA2dpResultHandler*) = {
-    [OPCODE_ERROR] = &BluetoothDaemonA2dpModule::ErrorRsp,
-    [OPCODE_CONNECT] = &BluetoothDaemonA2dpModule::ConnectRsp,
-    [OPCODE_DISCONNECT] = &BluetoothDaemonA2dpModule::DisconnectRsp
-  };
-
-  MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
-
-  if (NS_WARN_IF(!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(HandleRsp))) ||
-      NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
-    return;
-  }
-
-  RefPtr<BluetoothA2dpResultHandler> res =
-    static_cast<BluetoothA2dpResultHandler*>(aRes);
-
-  if (!res) {
-    return; // Return early if no result handler has been set for response
-  }
-
-  (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
-}
-
-// Notifications
-//
-
-// Returns the current notification handler to a notification runnable
-class BluetoothDaemonA2dpModule::NotificationHandlerWrapper final
-{
-public:
-  typedef BluetoothA2dpNotificationHandler ObjectType;
-
-  static ObjectType* GetInstance()
-  {