Bug 1372694 - Stop making the default theme a heavyweight theme. r=kmag,aswan draft
authorTim Nguyen <ntim.bugs@gmail.com>
Sun, 01 Apr 2018 13:53:31 +0200
changeset 786240 681cc4f30fafdee99c502b0419c96e9549914679
parent 786239 54e19e70e2e26c2b72f16c26c69688404ec04f75
child 786241 a75cc8a9b8e283776d1a75204d793bfa95e3e1bb
push id107411
push usermaglione.k@gmail.com
push dateSat, 21 Apr 2018 23:42:47 +0000
reviewerskmag, aswan
bugs1372694
milestone61.0a1
Bug 1372694 - Stop making the default theme a heavyweight theme. r=kmag,aswan MozReview-Commit-ID: 30wMauuc9oo
browser/app/moz.build
browser/app/profile/extensions/moz.build
browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in
browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/moz.build
browser/app/profile/firefox.js
browser/base/content/default-theme-icon.svg
browser/base/jar.mn
browser/components/customizableui/CustomizeMode.jsm
browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js
browser/installer/allowed-dupes.mn
browser/installer/package-manifest.in
browser/locales/en-US/chrome/browser/browser.properties
browser/themes/linux/jar.mn
browser/themes/osx/jar.mn
browser/themes/windows/jar.mn
toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/LightweightThemeManager.jsm
toolkit/mozapps/extensions/content/default-theme-icon.svg
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
toolkit/mozapps/extensions/internal/XPIInstall.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/internal/XPIProviderUtils.js
toolkit/mozapps/extensions/jar.mn
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js
toolkit/mozapps/extensions/test/xpcshell/test_addonStartup.js
toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js
toolkit/mozapps/extensions/test/xpcshell/test_badschema.js
toolkit/mozapps/extensions/test/xpcshell/test_manifest.js
toolkit/mozapps/extensions/test/xpcshell/test_strictcompatibility.js
toolkit/mozapps/extensions/test/xpcshell/test_webextension_theme.js
toolkit/themes/linux/mozapps/jar.mn
toolkit/themes/osx/global/jar.mn
toolkit/themes/osx/mozapps/jar.mn
toolkit/themes/shared/non-mac.jar.inc.mn
toolkit/themes/windows/global/jar.mn
toolkit/themes/windows/mozapps/jar.mn
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -19,26 +19,21 @@ with Files("macversion.py"):
 with Files("macbuild/**"):
     BUG_COMPONENT = ("Core", "Widget: Cocoa")
 
 with Files("moz.build"):
     BUG_COMPONENT = ("Firefox Build System", "General")
 with Files("Makefile.in"):
     BUG_COMPONENT = ("Firefox Build System", "General")
 
-with Files("profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/**"):
-    BUG_COMPONENT = ("Firefox", "Theme")
 with Files("profile/channel-prefs.js"):
     BUG_COMPONENT = ("Firefox", "Installer")
 with Files("profile/firefox.js"):
     BUG_COMPONENT = ("Firefox", "General")
 
-
-DIRS += ['profile/extensions']
-
 GeckoProgram(CONFIG['MOZ_APP_NAME'])
 
 SOURCES += [
     'nsBrowserApp.cpp',
 ]
 
 # Neither channel-prefs.js nor firefox.exe want to end up in dist/bin/browser.
 DIST_SUBDIR = ""
deleted file mode 100644
--- a/browser/app/profile/extensions/moz.build
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- Mode: python; 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 += ['{972ce4c6-7e08-4474-a285-3208198ce6fd}']
deleted file mode 100644
--- a/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-
-#filter substitution
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>{972ce4c6-7e08-4474-a285-3208198ce6fd}</em:id>
-    <em:version>@FIREFOX_VERSION@</em:version>
-
-    <!-- Target Application this theme can install into,
-        with minimum and maximum supported versions. -->
-    <em:targetApplication>
-      <Description>
-        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-        <em:minVersion>@FIREFOX_VERSION@</em:minVersion>
-        <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-
-    <!-- Front End MetaData -->
-    <em:name>Default</em:name>
-    <em:description>The default theme.</em:description>
-
-    <!-- Front End Integration Hooks (used by Theme Manager)-->
-    <em:creator>Mozilla</em:creator>
-    <em:contributor>Mozilla Contributors</em:contributor>
-
-    <!-- Allow lightweight themes to apply to this theme -->
-    <em:skinnable>true</em:skinnable>
-
-    <em:internalName>classic/1.0</em:internalName>
-
-    <em:iconURL>chrome://browser/content/default-theme-icon.svg</em:iconURL>
-  </Description>
-
-</RDF>
deleted file mode 100644
--- a/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/moz.build
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- Mode: python; 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/.
-
-FINAL_TARGET = 'dist/bin/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}'
-
-FINAL_TARGET_PP_FILES += [
-    'install.rdf.in',
-]
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -76,17 +76,17 @@ pref("extensions.geckoProfiler.getSymbol
 pref("extensions.webextensions.base-content-security-policy", "script-src 'self' https://* moz-extension: blob: filesystem: 'unsafe-eval' 'unsafe-inline'; object-src 'self' https://* moz-extension: blob: filesystem:;");
 pref("extensions.webextensions.default-content-security-policy", "script-src 'self'; object-src 'self';");
 
 #if defined(XP_WIN) || defined(XP_MACOSX)
 pref("extensions.webextensions.remote", true);
 #endif
 
 // Extensions that should not be flagged as legacy in about:addons
-pref("extensions.legacy.exceptions", "{972ce4c6-7e08-4474-a285-3208198ce6fd},testpilot@cliqz.com,@testpilot-containers,jid1-NeEaf3sAHdKHPA@jetpack,@activity-streams,pulse@mozilla.com,@testpilot-addon,@min-vid,tabcentertest1@mozilla.com,snoozetabs@mozilla.com,speaktome@mozilla.com,hoverpad@mozilla.com");
+pref("extensions.legacy.exceptions", "testpilot@cliqz.com,@testpilot-containers,jid1-NeEaf3sAHdKHPA@jetpack,@activity-streams,pulse@mozilla.com,@testpilot-addon,@min-vid,tabcentertest1@mozilla.com,snoozetabs@mozilla.com,speaktome@mozilla.com,hoverpad@mozilla.com");
 
 // Require signed add-ons by default
 pref("extensions.langpacks.signatures.required", true);
 pref("xpinstall.signatures.required", true);
 pref("xpinstall.signatures.devInfoURL", "https://wiki.mozilla.org/Addons/Extension_Signing");
 
 // Dictionary download preference
 pref("browser.dictionaries.download.url", "https://addons.mozilla.org/%LOCALE%/firefox/dictionaries/");
@@ -185,19 +185,16 @@ pref("app.update.service.enabled", true)
 //  .. etc ..
 //
 pref("extensions.update.enabled", true);
 pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 pref("extensions.update.interval", 86400);  // Check for updates to Extensions and
                                             // Themes every day
 
-pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
-pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
-
 pref("extensions.webextensions.themes.enabled", true);
 pref("extensions.webextensions.themes.icons.buttons", "back,forward,reload,stop,bookmark_star,bookmark_menu,downloads,home,app_menu,cut,copy,paste,new_window,new_private_window,save_page,print,history,full_screen,find,options,addons,developer,synced_tabs,open_file,sidebars,share_page,subscribe,text_encoding,email_link,forget,pocket");
 
 pref("lightweightThemes.update.enabled", true);
 pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
 pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#834d29\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"}]");
 
 #if defined(MOZ_WIDEVINE_EME)
@@ -1252,17 +1249,17 @@ pref("services.sync.prefs.sync.xpinstall
 // user's tabs and bookmarks. Note this pref is also synced.
 pref("services.sync.syncedTabs.showRemoteIcons", true);
 
 // Developer edition preferences
 #ifdef MOZ_DEV_EDITION
 pref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org",
      sticky);
 #else
-pref("lightweightThemes.selectedThemeID", "", sticky);
+pref("lightweightThemes.selectedThemeID", "default-theme@mozilla.org", sticky);
 #endif
 
 // Whether the character encoding menu is under the main Firefox button. This
 // preference is a string so that localizers can alter it.
 pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");
 
 // Allow using tab-modal prompts when possible.
 pref("prompts.tab_modal.enabled", true);
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -71,34 +71,33 @@ browser.jar:
         content/browser/browser-sync.js               (content/browser-sync.js)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
         content/browser/browser-tabsintitlebar.js       (content/browser-tabsintitlebar.js)
         content/browser/browser-thumbnails.js         (content/browser-thumbnails.js)
         content/browser/browser-trackingprotection.js (content/browser-trackingprotection.js)
         content/browser/browser-webrender.js          (content/browser-webrender.js)
         content/browser/tab-content.js                (content/tab-content.js)
         content/browser/content.js                    (content/content.js)
-        content/browser/default-theme-icon.svg        (content/default-theme-icon.svg)
         content/browser/defaultthemes/1.header.jpg    (content/defaultthemes/1.header.jpg)
         content/browser/defaultthemes/1.icon.jpg      (content/defaultthemes/1.icon.jpg)
         content/browser/defaultthemes/1.preview.jpg   (content/defaultthemes/1.preview.jpg)
         content/browser/defaultthemes/2.header.jpg    (content/defaultthemes/2.header.jpg)
         content/browser/defaultthemes/2.icon.jpg      (content/defaultthemes/2.icon.jpg)
         content/browser/defaultthemes/2.preview.jpg   (content/defaultthemes/2.preview.jpg)
         content/browser/defaultthemes/3.header.png    (content/defaultthemes/3.header.png)
         content/browser/defaultthemes/3.icon.png      (content/defaultthemes/3.icon.png)
         content/browser/defaultthemes/3.preview.png   (content/defaultthemes/3.preview.png)
         content/browser/defaultthemes/4.header.png    (content/defaultthemes/4.header.png)
         content/browser/defaultthemes/4.icon.png      (content/defaultthemes/4.icon.png)
         content/browser/defaultthemes/4.preview.png   (content/defaultthemes/4.preview.png)
         content/browser/defaultthemes/5.header.png    (content/defaultthemes/5.header.png)
         content/browser/defaultthemes/5.icon.jpg      (content/defaultthemes/5.icon.jpg)
         content/browser/defaultthemes/5.preview.jpg   (content/defaultthemes/5.preview.jpg)
-        content/browser/defaultthemes/dark.icon.svg  (content/defaultthemes/dark.icon.svg)
-        content/browser/defaultthemes/light.icon.svg (content/defaultthemes/light.icon.svg)
+        content/browser/defaultthemes/dark.icon.svg   (content/defaultthemes/dark.icon.svg)
+        content/browser/defaultthemes/light.icon.svg  (content/defaultthemes/light.icon.svg)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
         content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
         content/browser/pageinfo/feeds.js             (content/pageinfo/feeds.js)
         content/browser/pageinfo/permissions.js       (content/pageinfo/permissions.js)
         content/browser/pageinfo/security.js          (content/pageinfo/security.js)
         content/browser/robot.ico                     (content/robot.ico)
         content/browser/static-robot.png              (content/static-robot.png)
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -1334,18 +1334,18 @@ CustomizeMode.prototype = {
   updateAutoTouchMode(checked) {
     Services.prefs.setBoolPref("browser.touchmode.auto", checked);
     // Re-render the menu items since the active mode might have
     // change because of this.
     this.onUIDensityMenuShowing();
     this._onUIChange();
   },
 
-  async onLWThemesMenuShowing(aEvent) {
-    const DEFAULT_THEME_ID = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
+  onLWThemesMenuShowing(aEvent) {
+    const DEFAULT_THEME_ID = "default-theme@mozilla.org";
     const LIGHT_THEME_ID = "firefox-compact-light@mozilla.org";
     const DARK_THEME_ID = "firefox-compact-dark@mozilla.org";
     const MAX_THEME_COUNT = 6;
 
     this._clearLWThemesMenu(aEvent.target);
 
     function previewTheme(aPreviewThemeEvent) {
       LightweightThemeManager.previewTheme(
@@ -1358,31 +1358,23 @@ CustomizeMode.prototype = {
     }
 
     let onThemeSelected = panel => {
       this._updateLWThemeButtonIcon();
       this._onUIChange();
       panel.hidePopup();
     };
 
-    let aDefaultTheme = await AddonManager.getAddonByID(DEFAULT_THEME_ID);
     let doc = this.window.document;
 
     function buildToolbarButton(aTheme) {
       let tbb = doc.createElement("toolbarbutton");
       tbb.theme = aTheme;
       tbb.setAttribute("label", aTheme.name);
-      if (aDefaultTheme == aTheme) {
-        // The actual icon is set up so it looks nice in about:addons, but
-        // we'd like the version that's correct for the OS we're on, so we set
-        // an attribute that our styling will then use to display the icon.
-        tbb.setAttribute("defaulttheme", "true");
-      } else {
-        tbb.setAttribute("image", aTheme.iconURL);
-      }
+      tbb.setAttribute("image", aTheme.iconURL);
       if (aTheme.description)
         tbb.setAttribute("tooltiptext", aTheme.description);
       tbb.setAttribute("tabindex", "0");
       tbb.classList.add("customization-lwtheme-menu-theme");
       let isActive = activeThemeID == aTheme.id;
       tbb.setAttribute("aria-checked", isActive);
       tbb.setAttribute("role", "menuitemradio");
       if (isActive) {
@@ -1391,24 +1383,24 @@ CustomizeMode.prototype = {
       tbb.addEventListener("focus", previewTheme);
       tbb.addEventListener("mouseover", previewTheme);
       tbb.addEventListener("blur", resetPreview);
       tbb.addEventListener("mouseout", resetPreview);
 
       return tbb;
     }
 
-    let themes = [aDefaultTheme];
+    let themes = [];
     let lwts = LightweightThemeManager.usedThemes;
     let currentLwt = LightweightThemeManager.currentTheme;
 
     let activeThemeID = currentLwt ? currentLwt.id : DEFAULT_THEME_ID;
 
     // Move the current theme (if any) and the light/dark themes to the start:
-    let importantThemes = [LIGHT_THEME_ID, DARK_THEME_ID];
+    let importantThemes = [DEFAULT_THEME_ID, LIGHT_THEME_ID, DARK_THEME_ID];
     if (currentLwt && !importantThemes.includes(currentLwt.id)) {
       importantThemes.push(currentLwt.id);
     }
     for (let importantTheme of importantThemes) {
       let themeIndex = lwts.findIndex(theme => theme.id == importantTheme);
       if (themeIndex > -1) {
         themes.push(...lwts.splice(themeIndex, 1));
       }
--- a/browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js
+++ b/browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js
@@ -1,15 +1,15 @@
 /* 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 DEFAULT_THEME_ID = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
+const DEFAULT_THEME_ID = "default-theme@mozilla.org";
 const LIGHT_THEME_ID = "firefox-compact-light@mozilla.org";
 const DARK_THEME_ID = "firefox-compact-dark@mozilla.org";
 const {LightweightThemeManager} = ChromeUtils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
 
 add_task(async function() {
   Services.prefs.clearUserPref("lightweightThemes.usedThemes");
   Services.prefs.clearUserPref("lightweightThemes.recommendedThemes");
 
@@ -90,17 +90,18 @@ add_task(async function() {
     themeCount++;
     iterNode = iterNode.nextSibling;
   }
   is(themeCount, 4,
      "There should be four themes in the 'My Themes' section");
 
   let defaultTheme = header.nextSibling;
   defaultTheme.doCommand();
-  is(Services.prefs.getCharPref("lightweightThemes.selectedThemeID"), "", "No lwtheme should be selected");
+  is(Services.prefs.getCharPref("lightweightThemes.selectedThemeID"),
+     DEFAULT_THEME_ID, "Default theme should be selected");
 
   // ensure current theme isn't set to "Default"
   popupShownPromise = popupShown(popup);
   EventUtils.synthesizeMouseAtCenter(themesButton, {});
   info("Clicked on themes button a fourth time");
   await popupShownPromise;
 
   firstLWTheme = recommendedHeader.nextSibling;
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -76,17 +76,16 @@ browser/chrome/icons/default/default128.
 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
 chrome.manifest
 chrome/toolkit/skin/classic/global/autocomplete.css
 chrome/toolkit/skin/classic/global/button.css
 chrome/toolkit/skin/classic/global/checkbox.css
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -399,18 +399,16 @@
 #endif
 
 ; [Browser Chrome Files]
 @RESPATH@/browser/chrome.manifest
 @RESPATH@/browser/chrome/browser@JAREXT@
 @RESPATH@/browser/chrome/browser.manifest
 @RESPATH@/browser/chrome/pdfjs.manifest
 @RESPATH@/browser/chrome/pdfjs/*
-@RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/chrome.manifest
-@RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf
 @RESPATH@/chrome/toolkit@JAREXT@
 @RESPATH@/chrome/toolkit.manifest
 @RESPATH@/chrome/recording.manifest
 @RESPATH@/chrome/recording/*
 #ifdef MOZ_GTK
 @RESPATH@/browser/chrome/icons/default/default16.png
 @RESPATH@/browser/chrome/icons/default/default32.png
 @RESPATH@/browser/chrome/icons/default/default48.png
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -620,19 +620,16 @@ safebrowsing.reportedHarmfulSite=Reporte
 # of tabs in the current browser window. It will always be 2 at least.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 ctrlTab.listAllTabs.label=;List All #1 Tabs
 
 # LOCALIZATION NOTE (addKeywordTitleAutoFill): %S will be replaced by the page's title
 # Used as the bookmark name when saving a keyword for a search field.
 addKeywordTitleAutoFill=Search %S
 
-extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name=Default
-extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description=The default theme.
-
 # safeModeRestart
 safeModeRestartPromptTitle=Restart with Add-ons Disabled
 safeModeRestartPromptMessage=Are you sure you want to disable all add-ons and restart?
 safeModeRestartButton=Restart
 
 # LOCALIZATION NOTE (browser.menu.showCharacterEncoding): Set to the string
 # "true" (spelled and capitalized exactly that way) to show the "Text
 # Encoding" menu in the main Firefox button on Windows. Any other value will
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -46,13 +46,12 @@ browser.jar:
   skin/classic/browser/preferences/preferences.css    (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
 * skin/classic/browser/preferences/in-content/dialog.css      (preferences/in-content/dialog.css)
   skin/classic/browser/preferences/applications.css   (preferences/applications.css)
   skin/classic/browser/tabbrowser/tabDragIndicator.png      (tabbrowser/tabDragIndicator.png)
 
   skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
 
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
 % override chrome://browser/skin/feeds/audioFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/audioFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/videoFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/videoFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -56,14 +56,13 @@ browser.jar:
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
 * skin/classic/browser/preferences/in-content/dialog.css      (preferences/in-content/dialog.css)
   skin/classic/browser/preferences/applications.css         (preferences/applications.css)
   skin/classic/browser/share.svg                            (share.svg)
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabbrowser/tabDragIndicator@2x.png                (tabbrowser/tabDragIndicator@2x.png)
   skin/classic/browser/e10s-64@2x.png                                  (../shared/e10s-64@2x.png)
 
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
 % override chrome://browser/skin/feeds/audioFeedIcon.png                   chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/audioFeedIcon16.png                 chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/videoFeedIcon.png                   chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/videoFeedIcon16.png                 chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/notification-icons/geo-detailed.svg       chrome://browser/skin/notification-icons/geo.svg
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -57,14 +57,13 @@ browser.jar:
   skin/classic/browser/window-controls/minimize.svg              (window-controls/minimize.svg)
   skin/classic/browser/window-controls/minimize-highcontrast.svg (window-controls/minimize-highcontrast.svg)
   skin/classic/browser/window-controls/minimize-themes.svg       (window-controls/minimize-themes.svg)
   skin/classic/browser/window-controls/restore.svg               (window-controls/restore.svg)
   skin/classic/browser/window-controls/restore-highcontrast.svg  (window-controls/restore-highcontrast.svg)
   skin/classic/browser/window-controls/restore-themes.svg        (window-controls/restore-themes.svg)
   skin/classic/browser/e10s-64@2x.png                            (../shared/e10s-64@2x.png)
 
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
 % override chrome://browser/skin/page-livemarks.png                   chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/audioFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/audioFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/videoFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/videoFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
--- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
+++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
@@ -98,12 +98,16 @@ type.extension.name=Extensions
 type.themes.name=Themes
 type.locale.name=Languages
 type.plugin.name=Plugins
 type.dictionary.name=Dictionaries
 type.service.name=Services
 type.legacy.name=Legacy Extensions
 type.unsupported.name=Unsupported
 
+# LOCALIZATION NOTE (defaultTheme.name): This is displayed in about:addons -> Appearance
+defaultTheme.name=Default
+defaultTheme.description=The default theme.
+
 #LOCALIZATION NOTE(legacyWarning.description) %S is the brandShortName
 legacyWarning.description=Missing something? Some extensions are no longer supported by %S.
 #LOCALIZATION NOTE(legacyThemeWarning.description) %S is the brandShortName
 legacyThemeWarning.description=Missing something? Some themes are no longer supported by %S.
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -40,16 +40,18 @@ const PREF_WEBEXT_PERM_PROMPTS        = 
 const UPDATE_REQUEST_VERSION          = 2;
 
 const XMLURI_BLOCKLIST                = "http://www.mozilla.org/2006/addons-blocklist";
 
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_APPDIR                      = "XCurProcD";
 const FILE_BLOCKLIST                  = "blocklist.xml";
 
+const DEFAULT_THEME_ID                = "default-theme@mozilla.org";
+
 const BRANCH_REGEXP                   = /^([^\.]+\.[0-9]+[a-z]*).*/gi;
 const PREF_EM_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility";
 var PREF_EM_CHECK_COMPATIBILITY = MOZ_COMPATIBILITY_NIGHTLY ?
                                   PREF_EM_CHECK_COMPATIBILITY_BASE + ".nightly" :
                                   undefined;
 
 const VALID_TYPES_REGEXP = /^[\w\-]+$/;
 
@@ -65,16 +67,17 @@ const URI_XPINSTALL_DIALOG = "chrome://m
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/AsyncShutdown.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
   Extension: "resource://gre/modules/Extension.jsm",
   FileUtils: "resource://gre/modules/FileUtils.jsm",
+  LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
   PromptUtils: "resource://gre/modules/SharedPromptUtils.jsm",
 });
 
 XPCOMUtils.defineLazyPreferenceGetter(this, "WEBEXT_PERMISSION_PROMPTS",
                                       PREF_WEBEXT_PERM_PROMPTS, false);
 
 // Initialize the WebExtension process script service as early as possible,
 // since it needs to be able to track things like new frameLoader globals that
@@ -833,16 +836,32 @@ var AddonManagerInternal = {
 
       gStartupComplete = true;
       this.recordTimestamp("AMI_startup_end");
     } catch (e) {
       logger.error("startup failed", e);
       AddonManagerPrivate.recordException("AMI", "startup failed", e);
     }
 
+    let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
+    let extensionsBundle = Services.strings.createBundle(
+      "chrome://mozapps/locale/extensions/extensions.properties");
+
+    // When running in xpcshell tests, the default theme may already
+    // exist.
+    if (!LightweightThemeManager._builtInThemes.has(DEFAULT_THEME_ID)) {
+      LightweightThemeManager.addBuiltInTheme({
+        id: DEFAULT_THEME_ID,
+        name: extensionsBundle.GetStringFromName("defaultTheme.name"),
+        description: extensionsBundle.GetStringFromName("defaultTheme.description"),
+        iconURL: "chrome://mozapps/content/extensions/default-theme-icon.svg",
+        author: brandBundle.GetStringFromName("vendorShortName"),
+      });
+    }
+
     logger.debug("Completed startup sequence");
     this.callManagerListeners("onStartup");
   },
 
   /**
    * Registers a new AddonProvider.
    *
    * @param {string} aProvider -The provider to register
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -7,22 +7,22 @@
 var EXPORTED_SYMBOLS = ["LightweightThemeManager"];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 /* globals AddonManagerPrivate*/
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const ID_SUFFIX              = "@personas.mozilla.org";
-const PREF_LWTHEME_TO_SELECT = "extensions.lwThemeToSelect";
 const ADDON_TYPE             = "theme";
 const ADDON_TYPE_WEBEXT      = "webextension-theme";
 
 const URI_EXTENSION_STRINGS  = "chrome://mozapps/locale/extensions/extensions.properties";
 
+const DEFAULT_THEME_ID = "default-theme@mozilla.org";
 const DEFAULT_MAX_USED_THEMES_COUNT = 30;
 
 const MAX_PREVIEW_SECONDS = 30;
 
 const MANDATORY = ["id", "name"];
 const OPTIONAL = ["headerURL", "footerURL", "textcolor", "accentcolor",
                   "iconURL", "previewURL", "author", "description",
                   "homepageURL", "updateURL", "version"];
@@ -115,17 +115,17 @@ var LightweightThemeManager = {
       themes = JSON.parse(_prefs.getStringPref("usedThemes"));
     } catch (e) { }
 
     themes.push(...this._builtInThemes.values());
     return themes;
   },
 
   get currentTheme() {
-    let selectedThemeID = _prefs.getCharPref("selectedThemeID", "");
+    let selectedThemeID = _prefs.getStringPref("selectedThemeID", DEFAULT_THEME_ID);
 
     let data = null;
     if (selectedThemeID) {
       data = this.getUsedTheme(selectedThemeID);
     }
     return data;
   },
 
@@ -184,17 +184,17 @@ var LightweightThemeManager = {
 
   addBuiltInTheme(theme) {
     if (!theme || !theme.id || this.usedThemes.some(t => t.id == theme.id)) {
       throw new Error("Trying to add invalid builtIn theme");
     }
 
     this._builtInThemes.set(theme.id, theme);
 
-    if (_prefs.getCharPref("selectedThemeID") == theme.id) {
+    if (_prefs.getStringPref("selectedThemeID", DEFAULT_THEME_ID) == theme.id) {
       this.currentTheme = theme;
     }
   },
 
   forgetBuiltInTheme(id) {
     if (!this._builtInThemes.has(id)) {
       let currentTheme = this.currentTheme;
       if (currentTheme && currentTheme.id == id) {
@@ -318,25 +318,16 @@ var LightweightThemeManager = {
     Services.obs.notifyObservers(null, "lightweight-theme-changed");
   },
 
   /**
    * Starts the Addons provider and enables the new lightweight theme if
    * necessary.
    */
   startup() {
-    if (Services.prefs.prefHasUserValue(PREF_LWTHEME_TO_SELECT)) {
-      let id = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT);
-      if (id)
-        this.themeChanged(this.getUsedTheme(id));
-      else
-        this.themeChanged(null);
-      Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT);
-    }
-
     _prefs.addObserver("", _prefObserver);
   },
 
   /**
    * Shuts down the provider.
    */
   shutdown() {
     _prefs.removeObserver("", _prefObserver);
@@ -345,78 +336,54 @@ var LightweightThemeManager = {
   /**
    * Called when a new add-on has been enabled when only one add-on of that type
    * can be enabled.
    *
    * @param  aId
    *         The ID of the newly enabled add-on
    * @param  aType
    *         The type of the newly enabled add-on
-   * @param  aPendingRestart
-   *         true if the newly enabled add-on will only become enabled after a
-   *         restart
    */
-  addonChanged(aId, aType, aPendingRestart) {
+  addonChanged(aId, aType) {
     if (aType != ADDON_TYPE && aType != ADDON_TYPE_WEBEXT)
       return;
 
     let id = _getInternalID(aId);
     let current = this.currentTheme;
 
-    try {
-      let next = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT);
-      if (id == next && aPendingRestart)
-        return;
-
-      Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT);
-      if (next) {
-        AddonManagerPrivate.callAddonListeners("onOperationCancelled",
-                                               new AddonWrapper(this.getUsedTheme(next)));
-      } else if (id == current.id) {
-        AddonManagerPrivate.callAddonListeners("onOperationCancelled",
-                                               new AddonWrapper(current));
-        return;
-      }
-    } catch (e) {
+    if (current && id == current.id) {
+      AddonManagerPrivate.callAddonListeners("onOperationCancelled",
+                                             new AddonWrapper(current));
+      return;
     }
 
     if (current) {
-      if (current.id == id)
+      if (current.id == id || (!aId && current.id == DEFAULT_THEME_ID))
         return;
       _themeIDBeingDisabled = current.id;
       let wrapper = new AddonWrapper(current);
-      if (aPendingRestart) {
-        Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, "");
-        AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, true);
-      } else {
-        AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, false);
-        this.themeChanged(null);
-        AddonManagerPrivate.callAddonListeners("onDisabled", wrapper);
-      }
+
+      AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, false);
+      this.themeChanged(null);
+      AddonManagerPrivate.callAddonListeners("onDisabled", wrapper);
       _themeIDBeingDisabled = null;
     }
 
     if (id) {
       let theme = this.getUsedTheme(id);
       // WebExtension themes have an ID, but no LWT wrapper, so bail out here.
       if (!theme)
         return;
       _themeIDBeingEnabled = id;
       let wrapper = new AddonWrapper(theme);
-      if (aPendingRestart) {
-        AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, true);
-        Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, id);
 
-        // Flush the preferences to disk so they survive any crash
-        Services.prefs.savePrefFile(null);
-      } else {
-        AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, false);
-        this.themeChanged(theme);
-        AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
-      }
+      AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, false);
+      this.themeChanged(theme);
+      AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
+
       _themeIDBeingEnabled = null;
     }
   },
 
   /**
    * Called to get an Addon with a particular ID.
    *
    * @param  aId
@@ -459,17 +426,17 @@ let themeFor = wrapper => wrapperMap.get
  * consumers of the AddonManager API.
  */
 function AddonWrapper(aTheme) {
   wrapperMap.set(this, aTheme);
 }
 
 AddonWrapper.prototype = {
   get id() {
-    return themeFor(this).id + ID_SUFFIX;
+    return _getExternalID(themeFor(this).id);
   },
 
   get type() {
     return ADDON_TYPE;
   },
 
   get isActive() {
     let current = LightweightThemeManager.currentTheme;
@@ -517,35 +484,30 @@ AddonWrapper.prototype = {
   get permissions() {
     let permissions = 0;
 
     // Do not allow uninstall of builtIn themes.
     if (!LightweightThemeManager._builtInThemes.has(themeFor(this).id))
       permissions = AddonManager.PERM_CAN_UNINSTALL;
     if (this.userDisabled)
       permissions |= AddonManager.PERM_CAN_ENABLE;
-    else
+    else if (themeFor(this).id != DEFAULT_THEME_ID)
       permissions |= AddonManager.PERM_CAN_DISABLE;
     return permissions;
   },
 
   get userDisabled() {
     let id = themeFor(this).id;
     if (_themeIDBeingEnabled == id)
       return false;
     if (_themeIDBeingDisabled == id)
       return true;
 
-    try {
-      let toSelect = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT);
-      return id != toSelect;
-    } catch (e) {
-      let current = LightweightThemeManager.currentTheme;
-      return !current || current.id != id;
-    }
+    let current = LightweightThemeManager.currentTheme;
+    return !current || current.id != id;
   },
 
   set userDisabled(val) {
     if (val == this.userDisabled)
       return val;
 
     if (val)
       LightweightThemeManager.currentTheme = null;
@@ -633,22 +595,30 @@ AddonWrapper.prototype = {
  *          The ID to be converted
  *
  * @return  the lightweight theme ID or null if the ID was not for a lightweight
  *          theme.
  */
 function _getInternalID(id) {
   if (!id)
     return null;
+  if (id == DEFAULT_THEME_ID)
+    return id;
   let len = id.length - ID_SUFFIX.length;
   if (len > 0 && id.substring(len) == ID_SUFFIX)
     return id.substring(0, len);
   return null;
 }
 
+function _getExternalID(id) {
+  if (id == DEFAULT_THEME_ID)
+    return id;
+  return id + ID_SUFFIX;
+}
+
 function _setCurrentTheme(aData, aLocal) {
   aData = _sanitizeTheme(aData, null, aLocal);
 
   let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
   cancel.data = false;
   Services.obs.notifyObservers(cancel, "lightweight-theme-change-requested",
                                JSON.stringify(aData));
 
@@ -686,17 +656,17 @@ function _setCurrentTheme(aData, aLocal)
     if (isInstall)
       AddonManagerPrivate.callAddonListeners("onInstalled", wrapper);
   }
 
   if (cancel.data)
     return null;
 
   if (notify) {
-    AddonManagerPrivate.notifyAddonChanged(aData ? aData.id + ID_SUFFIX : null,
+    AddonManagerPrivate.notifyAddonChanged(aData ? _getExternalID(aData.id) : null,
                                            ADDON_TYPE, false);
   }
 
   return LightweightThemeManager.currentTheme;
 }
 
 function _sanitizeTheme(aData, aBaseURI, aLocal) {
   if (!aData || typeof aData != "object")
rename from browser/base/content/default-theme-icon.svg
rename to toolkit/mozapps/extensions/content/default-theme-icon.svg
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -240,17 +240,18 @@ function isLegacyExtension(addon) {
     legacy = true;
   }
   if (addon.type == "theme") {
     // The logic here is kind of clunky but we want to mark complete
     // themes as legacy.  There's no explicit flag for complete
     // themes so explicitly check for new style themes (for which
     // isWebExtension is true) or lightweight themes (which have
     // ids that end with @personas.mozilla.org)
-    legacy = !(addon.isWebExtension || addon.id.endsWith("@personas.mozilla.org"));
+    legacy = !(addon.isWebExtension || addon.id.endsWith("@personas.mozilla.org") ||
+               addon.id == "default-theme@mozilla.org");
   }
 
   if (legacy && (addon.hidden || addon.signedState == AddonManager.SIGNEDSTATE_PRIVILEGED)) {
     legacy = false;
   }
   // Exceptions that can slip through above: the default theme plus
   // test pilot addons until we get SIGNEDSTATE_PRIVILEGED deployed.
   if (legacy && legacyWarningExceptions.includes(addon.id)) {
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -954,16 +954,18 @@ var AddonTestUtils = {
    */
   writeFilesToZip(zipFile, files, flags = 0) {
     if (typeof zipFile == "string")
       zipFile = nsFile(zipFile);
 
     var zipW = ZipWriter(zipFile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | flags);
 
     for (let [path, data] of Object.entries(files)) {
+      if (typeof data === "object" && ChromeUtils.getClassName(data) === "Object")
+        data = JSON.stringify(data);
       if (!(data instanceof ArrayBuffer))
         data = new TextEncoder("utf-8").encode(data).buffer;
 
       let stream = ArrayBufferInputStream(data, 0, data.byteLength);
 
       // Note these files are being created in the XPI archive with date "0" which is 1970-01-01.
       zipW.addEntryStream(path, 0, Ci.nsIZipWriter.COMPRESSION_NONE,
                           stream, false);
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -66,18 +66,16 @@ XPCOMUtils.defineLazyServiceGetters(this
 
 ChromeUtils.defineModuleGetter(this, "XPIInternal",
                                "resource://gre/modules/addons/XPIProvider.jsm");
 ChromeUtils.defineModuleGetter(this, "XPIProvider",
                                "resource://gre/modules/addons/XPIProvider.jsm");
 
 const PREF_ALLOW_NON_RESTARTLESS      = "extensions.legacy.non-restartless.enabled";
 
-const DEFAULT_SKIN = "classic/1.0";
-
 /* globals AddonInternal, BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, TEMPORARY_ADDON_SUFFIX, SIGNED_TYPES, TOOLKIT_ID, XPIDatabase, XPIStates, getExternalType, isTheme, isUsableAddon, isWebExtension, mustSign, recordAddonTelemetry */
 const XPI_INTERNAL_SYMBOLS = [
   "AddonInternal",
   "BOOTSTRAP_REASONS",
   "KEY_APP_SYSTEM_ADDONS",
   "KEY_APP_SYSTEM_DEFAULTS",
   "KEY_APP_TEMPORARY",
   "SIGNED_TYPES",
@@ -153,24 +151,23 @@ const PROP_METADATA      = ["id", "versi
                             "optionsURL", "optionsType", "aboutURL",
                             "iconURL", "icon64URL"];
 const PROP_LOCALE_SINGLE = ["name", "description", "creator", "homepageURL"];
 const PROP_LOCALE_MULTI  = ["developers", "translators", "contributors"];
 const PROP_TARGETAPP     = ["id", "minVersion", "maxVersion"];
 
 // Map new string type identifiers to old style nsIUpdateItem types.
 // Retired values:
-// 8 = locale
 // 32 = multipackage xpi file
 // 8 = locale
 // 256 = apiextension
 // 128 = experiment
+// theme = 4
 const TYPES = {
   extension: 2,
-  theme: 4,
   dictionary: 64,
 };
 
 const COMPATIBLE_BY_DEFAULT_TYPES = {
   extension: true,
   dictionary: true,
 };
 
@@ -796,26 +793,17 @@ async function loadManifestFromRDF(aUri,
       platform.abi = targetPlatform.substring(pos + 1);
     } else {
       platform.os = targetPlatform;
     }
 
     addon.targetPlatforms.push(platform);
   }
 
-  // A theme's userDisabled value is true if the theme is not the selected skin
-  // or if there is an active lightweight theme. We ignore whether softblocking
-  // is in effect since it would change the active theme.
-  if (isTheme(addon.type)) {
-    addon.userDisabled = !!LightweightThemeManager.currentTheme ||
-                         addon.internalName != DEFAULT_SKIN;
-  } else {
-    addon.userDisabled = false;
-  }
-
+  addon.userDisabled = false;
   addon.softDisabled = addon.blocklistState == nsIBlocklistService.STATE_SOFTBLOCKED;
   addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;
 
   // icons will be filled by the calling function
   addon.icons = {};
   addon.userPermissions = null;
 
   return addon;
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -82,18 +82,16 @@ const PREF_SYSTEM_ADDON_SET           = 
 const PREF_SYSTEM_ADDON_UPDATE_URL    = "extensions.systemAddon.update.url";
 const PREF_ALLOW_LEGACY               = "extensions.legacy.enabled";
 
 const PREF_EM_MIN_COMPAT_APP_VERSION      = "extensions.minCompatibleAppVersion";
 const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
 
 const PREF_EM_LAST_APP_BUILD_ID       = "extensions.lastAppBuildId";
 
-const DEFAULT_SKIN = "classic/1.0";
-
 // Specify a list of valid built-in add-ons to load.
 const BUILT_IN_ADDONS_URI             = "chrome://browser/content/built_in_addons.json";
 
 const OBSOLETE_PREFERENCES = [
   "extensions.bootstrappedAddons",
   "extensions.enabledAddons",
   "extensions.xpiState",
   "extensions.installCache",
@@ -107,47 +105,47 @@ const DIR_STAGE                       = 
 const DIR_TRASH                       = "trash";
 
 const FILE_XPI_STATES                 = "addonStartup.json.lz4";
 const FILE_DATABASE                   = "extensions.json";
 const FILE_RDF_MANIFEST               = "install.rdf";
 const FILE_WEB_MANIFEST               = "manifest.json";
 const FILE_XPI_ADDONS_LIST            = "extensions.ini";
 
-const ADDON_ID_DEFAULT_THEME          = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
-
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_ADDON_APP_DIR               = "XREAddonAppDir";
 const KEY_APP_DISTRIBUTION            = "XREAppDist";
 const KEY_APP_FEATURES                = "XREAppFeat";
 
 const KEY_APP_PROFILE                 = "app-profile";
 const KEY_APP_SYSTEM_ADDONS           = "app-system-addons";
 const KEY_APP_SYSTEM_DEFAULTS         = "app-system-defaults";
 const KEY_APP_GLOBAL                  = "app-global";
 const KEY_APP_SYSTEM_LOCAL            = "app-system-local";
 const KEY_APP_SYSTEM_SHARE            = "app-system-share";
 const KEY_APP_SYSTEM_USER             = "app-system-user";
 const KEY_APP_TEMPORARY               = "app-temporary";
 
+const DEFAULT_THEME_ID = "default-theme@mozilla.org";
+
 const TEMPORARY_ADDON_SUFFIX = "@temporary-addon";
 
 const STARTUP_MTIME_SCOPES = [KEY_APP_GLOBAL,
                               KEY_APP_SYSTEM_LOCAL,
                               KEY_APP_SYSTEM_SHARE,
                               KEY_APP_SYSTEM_USER];
 
 const NOTIFICATION_FLUSH_PERMISSIONS  = "flush-pending-permissions";
 const XPI_PERMISSION                  = "install";
 
 const TOOLKIT_ID                      = "toolkit@mozilla.org";
 
 const XPI_SIGNATURE_CHECK_PERIOD      = 24 * 60 * 60;
 
-XPCOMUtils.defineConstant(this, "DB_SCHEMA", 24);
+XPCOMUtils.defineConstant(this, "DB_SCHEMA", 25);
 
 const NOTIFICATION_TOOLBOX_CONNECTION_CHANGE      = "toolbox-connection-change";
 
 // Properties that exist in the install manifest
 const PROP_LOCALE_SINGLE = ["name", "description", "creator", "homepageURL"];
 const PROP_LOCALE_MULTI  = ["developers", "translators", "contributors"];
 
 // Properties to cache and reload when an addon installation is pending
@@ -206,17 +204,16 @@ const SIGNED_TYPES = new Set([
   "extension",
   "webextension",
   "webextension-langpack",
   "webextension-theme",
 ]);
 
 const LEGACY_TYPES = new Set([
   "extension",
-  "theme",
 ]);
 
 const ALL_EXTERNAL_TYPES = new Set([
   "dictionary",
   "extension",
   "locale",
   "theme",
 ]);
@@ -284,17 +281,16 @@ function loadLazyObjects() {
     wantGlobalProperties: ["ChromeUtils", "TextDecoder"],
   });
 
   Object.assign(scope, {
     ADDON_SIGNING: AddonSettings.ADDON_SIGNING,
     SIGNED_TYPES,
     BOOTSTRAP_REASONS,
     DB_SCHEMA,
-    DEFAULT_SKIN,
     AddonInternal,
     XPIProvider,
     XPIStates,
     syncLoadManifestFromFile,
     isUsableAddon,
     recordAddonTelemetry,
     flushChromeCaches: XPIInstall.flushChromeCaches,
     descriptorToPath,
@@ -786,19 +782,16 @@ function isDisabledLegacy(addon) {
 /**
  * Calculates whether an add-on should be appDisabled or not.
  *
  * @param  aAddon
  *         The add-on to check
  * @return true if the add-on should not be appDisabled
  */
 function isUsableAddon(aAddon) {
-  if (aAddon.type == "theme")
-    return aAddon.internalName == DEFAULT_SKIN;
-
   if (mustSign(aAddon.type) && !aAddon.isCorrectlySigned) {
     logger.warn(`Add-on ${aAddon.id} is not correctly signed.`);
     if (Services.prefs.getBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, false)) {
       logger.warn(`Preference ${PREF_XPI_SIGNATURES_DEV_ROOT} is set.`);
     }
     return false;
   }
 
@@ -1196,24 +1189,17 @@ class XPIState {
   syncWithDB(aDBAddon, aUpdated = false) {
     logger.debug("Updating XPIState for " + JSON.stringify(aDBAddon));
     // If the add-on changes from disabled to enabled, we should re-check the modified time.
     // If this is a newly found add-on, it won't have an 'enabled' field but we
     // did a full recursive scan in that case, so we don't need to do it again.
     // We don't use aDBAddon.active here because it's not updated until after restart.
     let mustGetMod = (aDBAddon.visible && !aDBAddon.disabled && !this.enabled);
 
-    // We need to treat XUL themes specially here, since lightweight
-    // themes require the default theme's chrome to be registered even
-    // though we report it as disabled for UI purposes.
-    if (aDBAddon.type == "theme") {
-      this.enabled = aDBAddon.internalName == DEFAULT_SKIN;
-    } else {
-      this.enabled = aDBAddon.visible && !aDBAddon.disabled;
-    }
+    this.enabled = aDBAddon.visible && !aDBAddon.disabled;
 
     this.version = aDBAddon.version;
     this.type = aDBAddon.type;
     if (aDBAddon.startupData) {
       this.startupData = aDBAddon.startupData;
     }
 
     this.bootstrapped = !!aDBAddon.bootstrap;
@@ -2056,19 +2042,16 @@ var XPIProvider = {
         // effect
         Services.obs.notifyObservers(null, "chrome-flush-skin-caches");
         Services.obs.notifyObservers(null, "chrome-flush-caches");
       }
 
       if (AppConstants.MOZ_CRASHREPORTER) {
         // Annotate the crash report with relevant add-on information.
         try {
-          Services.appinfo.annotateCrashReport("Theme", DEFAULT_SKIN);
-        } catch (e) { }
-        try {
           Services.appinfo.annotateCrashReport("EMCheckCompatibility",
                                                AddonManager.checkCompatibility);
         } catch (e) { }
         this.addAddonsToCrashReporter();
       }
 
       try {
         AddonManagerPrivate.recordTimestamp("XPI_bootstrap_addons_begin");
@@ -2879,40 +2862,16 @@ var XPIProvider = {
   },
 
   getDependentAddons(aAddon) {
     return Array.from(XPIDatabase.getAddons())
                 .filter(addon => addon.dependencies.includes(aAddon.id));
   },
 
   /**
-   * Returns the add-on state data for the restartful extensions which
-   * should be available in safe mode. In particular, this means the
-   * default theme, and only the default theme.
-   *
-   * @returns {object}
-   */
-  getSafeModeExtensions() {
-    let loc = XPIStates.getLocation(KEY_APP_GLOBAL);
-    let state = loc.get(ADDON_ID_DEFAULT_THEME);
-
-    // Use the default state data for the default theme, but always mark
-    // it enabled, in case another theme is enabled in normal mode.
-    let addonData = state.toJSON();
-    addonData.enabled = true;
-
-    return {
-      [KEY_APP_GLOBAL]: {
-        path: loc.path,
-        addons: { [ADDON_ID_DEFAULT_THEME]: addonData },
-      },
-    };
-  },
-
-  /**
    * Checks for any changes that have occurred since the last time the
    * application was launched.
    *
    * @param  aAppChanged
    *         A tri-state value. Undefined means the current profile was created
    *         for this session, true means the profile already existed but was
    *         last used with an application with a different version number,
    *         false means that the profile was last used by this version of the
@@ -3001,35 +2960,23 @@ var XPIProvider = {
                                                                          aOldAppVersion,
                                                                          aOldPlatformVersion,
                                                                          updateReasons.includes("schemaChanged"));
         } catch (e) {
           logger.error("Failed to process extension changes at startup", e);
         }
       }
 
-      if (Services.appinfo.inSafeMode) {
-        aomStartup.initializeExtensions(this.getSafeModeExtensions());
-        logger.debug("Initialized safe mode add-ons");
-        return false;
-      }
-
       // If the application crashed before completing any pending operations then
       // we should perform them now.
       if (extensionListChanged || hasPendingChanges) {
         this._updateActiveAddons();
-
-        // Serialize and deserialize so we get the expected JSON data.
-        let state = JSON.parse(JSON.stringify(XPIStates));
-        aomStartup.initializeExtensions(state);
         return true;
       }
 
-      aomStartup.initializeExtensions(XPIStates.initialStateData);
-
       logger.debug("No changes found");
     } catch (e) {
       logger.error("Error during startup file checks", e);
     }
 
     return false;
   },
 
@@ -3565,24 +3512,31 @@ var XPIProvider = {
    * @param  aType
    *         The type of the newly enabled add-on
    */
   addonChanged(aId, aType) {
     // We only care about themes in this provider
     if (!isTheme(aType))
       return;
 
-    let addons = XPIDatabase.getAddonsByType("theme", "webextension-theme");
+    let addons = XPIDatabase.getAddonsByType("webextension-theme");
     for (let theme of addons) {
-      if (isWebExtension(theme.type) && theme.visible && theme.id != aId)
-        this.updateAddonDisabledState(theme, true, undefined);
-    }
-
-    let defaultTheme = XPIDatabase.getVisibleAddonForInternalName(DEFAULT_SKIN);
-    this.updateAddonDisabledState(defaultTheme, aId && aId != defaultTheme.id);
+      if (theme.visible && theme.id != aId)
+        this.updateAddonDisabledState(theme, true, undefined, true);
+    }
+
+    if (!aId && (!LightweightThemeManager.currentTheme ||
+                 LightweightThemeManager.currentTheme !== DEFAULT_THEME_ID)) {
+      let theme = LightweightThemeManager.getUsedTheme(DEFAULT_THEME_ID);
+      // This can only ever be null in tests.
+      // This can all go away once lightweight themes are gone.
+      if (theme) {
+        LightweightThemeManager.currentTheme = theme;
+      }
+    }
   },
 
   /**
    * Update the appDisabled property for all add-ons.
    */
   updateAddonAppDisabledStates() {
     let addons = XPIDatabase.getAddons();
     for (let addon of addons) {
@@ -3909,23 +3863,26 @@ var XPIProvider = {
    * @param  aAddon
    *         The DBAddonInternal to update
    * @param  aUserDisabled
    *         Value for the userDisabled property. If undefined the value will
    *         not change
    * @param  aSoftDisabled
    *         Value for the softDisabled property. If undefined the value will
    *         not change. If true this will force userDisabled to be true
+   * @param {boolean} aBecauseSelecting
+   *        True if we're disabling this add-on because we're selecting
+   *        another.
    * @return a tri-state indicating the action taken for the add-on:
    *           - undefined: The add-on did not change state
    *           - true: The add-on because disabled
    *           - false: The add-on became enabled
    * @throws if addon is not a DBAddonInternal
    */
-  updateAddonDisabledState(aAddon, aUserDisabled, aSoftDisabled) {
+  updateAddonDisabledState(aAddon, aUserDisabled, aSoftDisabled, aBecauseSelecting) {
     if (!(aAddon.inDatabase))
       throw new Error("Can only update addon states for installed addons.");
     if (aUserDisabled !== undefined && aSoftDisabled !== undefined) {
       throw new Error("Cannot change userDisabled and softDisabled at the " +
                       "same time");
     }
 
     if (aUserDisabled === undefined) {
@@ -4011,22 +3968,26 @@ var XPIProvider = {
           this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "startup",
                                    BOOTSTRAP_REASONS.ADDON_ENABLE);
         }
         AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
       }
     }
 
     // Notify any other providers that a new theme has been enabled
-    if (isTheme(aAddon.type) && !isDisabled) {
-      AddonManagerPrivate.notifyAddonChanged(aAddon.id, aAddon.type);
-
-      if (xpiState) {
-        xpiState.syncWithDB(aAddon);
-        XPIStates.save();
+    if (isTheme(aAddon.type)) {
+      if (!isDisabled) {
+        AddonManagerPrivate.notifyAddonChanged(aAddon.id, aAddon.type);
+
+        if (xpiState) {
+          xpiState.syncWithDB(aAddon);
+          XPIStates.save();
+        }
+      } else if (isDisabled && !aBecauseSelecting) {
+        AddonManagerPrivate.notifyAddonChanged(null, "theme");
       }
     }
 
     return isDisabled;
   },
 
   /**
    * Uninstalls an add-on, immediately if possible or marks it as pending
@@ -4763,18 +4724,17 @@ AddonWrapper.prototype = {
       if (this.hasResource("icon.png")) {
         icons[32] = icons[48] = this.getResourceURI("icon.png").spec;
       }
       if (this.hasResource("icon64.png")) {
         icons[64] = this.getResourceURI("icon64.png").spec;
       }
     }
 
-    let canUseIconURLs = this.isActive ||
-      (addon.type == "theme" && addon.internalName == DEFAULT_SKIN);
+    let canUseIconURLs = this.isActive;
     if (canUseIconURLs && addon.iconURL) {
       icons[32] = addon.iconURL;
       icons[48] = addon.iconURL;
     }
 
     if (canUseIconURLs && addon.icon64URL) {
       icons[64] = addon.icon64URL;
     }
@@ -4926,26 +4886,18 @@ AddonWrapper.prototype = {
   },
   set userDisabled(val) {
     let addon = addonFor(this);
     if (val == this.userDisabled) {
       return val;
     }
 
     if (addon.inDatabase) {
-      let theme = isTheme(addon.type);
-      if (theme && val) {
-        if (addon.internalName == DEFAULT_SKIN)
-          throw new Error("Cannot disable the default theme");
-
-        let defaultTheme = XPIDatabase.getVisibleAddonForInternalName(DEFAULT_SKIN);
-        XPIProvider.updateAddonDisabledState(defaultTheme, false);
-      }
-      if (!(theme && val) || isWebExtension(addon.type)) {
-        // hidden and system add-ons should not be user disasbled,
+      if (!(isTheme(addon.type) && val) || isWebExtension(addon.type)) {
+        // hidden and system add-ons should not be user disabled,
         // as there is no UI to re-enable them.
         if (this.hidden) {
           throw new Error(`Cannot disable hidden add-on ${addon.id}`);
         }
         XPIProvider.updateAddonDisabledState(addon, val);
       }
     } else {
       addon.userDisabled = val;
@@ -4960,18 +4912,16 @@ AddonWrapper.prototype = {
   set softDisabled(val) {
     let addon = addonFor(this);
     if (val == addon.softDisabled)
       return val;
 
     if (addon.inDatabase) {
       // When softDisabling a theme just enable the active theme
       if (isTheme(addon.type) && val && !addon.userDisabled) {
-        if (addon.internalName == DEFAULT_SKIN)
-          throw new Error("Cannot disable the default theme");
         if (isWebExtension(addon.type))
           XPIProvider.updateAddonDisabledState(addon, undefined, val);
       } else {
         XPIProvider.updateAddonDisabledState(addon, undefined, val);
       }
     } else if (!addon.userDisabled) {
       // Only set softDisabled if not already disabled
       addon.softDisabled = val;
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // These are injected from XPIProvider.jsm
 /* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA,
           AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile,
           isUsableAddon, recordAddonTelemetry,
-          flushChromeCaches, descriptorToPath, DEFAULT_SKIN */
+          flushChromeCaches, descriptorToPath */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AddonManager: "resource://gre/modules/AddonManager.jsm",
   AddonManagerPrivate: "resource://gre/modules/AddonManager.jsm",
   AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
   DeferredTask: "resource://gre/modules/DeferredTask.jsm",
@@ -43,17 +43,17 @@ const PREF_EM_AUTO_DISABLED_SCOPES    = 
 
 const KEY_APP_SYSTEM_ADDONS           = "app-system-addons";
 const KEY_APP_SYSTEM_DEFAULTS         = "app-system-defaults";
 const KEY_APP_GLOBAL                  = "app-global";
 const KEY_APP_TEMPORARY               = "app-temporary";
 
 // Properties to save in JSON file
 const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
-                          "internalName", "updateURL", "optionsURL",
+                          "updateURL", "optionsURL",
                           "optionsType", "optionsBrowserStyle", "aboutURL",
                           "defaultLocale", "visible", "active", "userDisabled",
                           "appDisabled", "pendingUninstall", "installDate",
                           "updateDate", "applyBackgroundUpdates", "bootstrap", "path",
                           "skinnable", "size", "sourceURI", "releaseNotesURI",
                           "softDisabled", "foreignInstall",
                           "strictCompatibility", "locales", "targetApplications",
                           "targetPlatforms", "signedState",
@@ -707,38 +707,16 @@ this.XPIDatabase = {
       AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_byType", XPIProvider.runPhase);
       this.syncLoadDB(true);
     }
 
     return _filterDB(this.addonDB, aAddon => aTypes.includes(aAddon.type));
   },
 
   /**
-   * Synchronously gets an add-on with a particular internalName.
-   *
-   * @param  aInternalName
-   *         The internalName of the add-on to retrieve
-   * @return a DBAddonInternal
-   */
-  getVisibleAddonForInternalName(aInternalName) {
-    if (!this.addonDB) {
-      // This may be called when the DB hasn't otherwise been loaded
-      logger.warn(`Synchronous load of XPI database due to ` +
-                  `getVisibleAddonForInternalName. Stack: ${Error().stack}`);
-      AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_forInternalName",
-          XPIProvider.runPhase);
-      this.syncLoadDB(true);
-    }
-
-    return _findAddon(this.addonDB,
-                      aAddon => aAddon.visible &&
-                                (aAddon.internalName == aInternalName));
-  },
-
-  /**
    * Asynchronously gets all add-ons with pending operations.
    *
    * @param  aTypes
    *         The types of add-ons to retrieve or null to get all types
    */
   getVisibleAddonsWithPendingOperations(aTypes) {
     return this.getAddonList(
         aAddon => (aAddon.visible &&
@@ -1090,20 +1068,16 @@ this.XPIDatabaseReconcile = {
     // foreign and should default to enabled.
     aNewAddon.foreignInstall = isDetectedInstall &&
                                aInstallLocation.name != KEY_APP_SYSTEM_ADDONS &&
                                aInstallLocation.name != KEY_APP_SYSTEM_DEFAULTS;
 
     // appDisabled depends on whether the add-on is a foreignInstall so update
     aNewAddon.appDisabled = !isUsableAddon(aNewAddon);
 
-    // The default theme is never a foreign install
-    if (aNewAddon.type == "theme" && aNewAddon.internalName == DEFAULT_SKIN)
-      aNewAddon.foreignInstall = false;
-
     if (isDetectedInstall && aNewAddon.foreignInstall) {
       // If the add-on is a foreign install and is in a scope where add-ons
       // that were dropped in should default to disabled then disable it
       let disablingScopes = Services.prefs.getIntPref(PREF_EM_AUTO_DISABLED_SCOPES, 0);
       if (aInstallLocation.scope & disablingScopes) {
         logger.warn("Disabling foreign installed add-on " + aNewAddon.id + " in "
             + aInstallLocation.name);
         aNewAddon.userDisabled = true;
@@ -1455,21 +1429,17 @@ this.XPIDatabaseReconcile = {
       if (!previousAddon) {
         // If we had a manifest for this add-on it was a staged install and
         // so wasn't something recovered from a corrupt database
         let wasStaged = !!loadedManifest(currentAddon._installLocation, id);
 
         // We might be recovering from a corrupt database, if so use the
         // list of known active add-ons to update the new add-on
         if (!wasStaged && XPIDatabase.activeBundles) {
-          // For themes we know which is active by the current skin setting
-          if (currentAddon.type == "theme")
-            isActive = currentAddon.internalName == DEFAULT_SKIN;
-          else
-            isActive = XPIDatabase.activeBundles.includes(currentAddon.path);
+          isActive = XPIDatabase.activeBundles.includes(currentAddon.path);
 
           if (currentAddon.type == "webextension-theme")
             currentAddon.userDisabled = !isActive;
 
           // If the add-on wasn't active and it isn't already disabled in some way
           // then it was probably either softDisabled or userDisabled
           if (!isActive && !currentAddon.disabled) {
             // If the add-on is softblocked then assume it is softDisabled
--- a/toolkit/mozapps/extensions/jar.mn
+++ b/toolkit/mozapps/extensions/jar.mn
@@ -17,13 +17,14 @@ toolkit.jar:
   content/mozapps/extensions/update.html                        (content/update.html)
   content/mozapps/extensions/update.js                          (content/update.js)
   content/mozapps/extensions/update.css                         (content/update.css)
   content/mozapps/extensions/eula.xul                           (content/eula.xul)
   content/mozapps/extensions/eula.js                            (content/eula.js)
   content/mozapps/extensions/pluginPrefs.xul                    (content/pluginPrefs.xul)
   content/mozapps/extensions/pluginPrefs.js                     (content/pluginPrefs.js)
   content/mozapps/extensions/OpenH264-license.txt               (content/OpenH264-license.txt)
+  content/mozapps/extensions/default-theme-icon.svg             (content/default-theme-icon.svg)
 #endif
   content/mozapps/xpinstall/xpinstallConfirm.xul                (content/xpinstallConfirm.xul)
   content/mozapps/xpinstall/xpinstallConfirm.js                 (content/xpinstallConfirm.js)
   content/mozapps/xpinstall/xpinstallConfirm.css                (content/xpinstallConfirm.css)
   content/mozapps/xpinstall/xpinstallItem.xml                   (content/xpinstallItem.xml)
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -1105,17 +1105,17 @@ function check_test_completed(aArgs) {
 
   return gNext.apply(null, aArgs);
 }
 
 // Verifies that all the expected events for all add-ons were seen
 function ensure_test_completed() {
   for (let i in gExpectedEvents) {
     if (gExpectedEvents[i].length > 0)
-      do_throw("Didn't see all the expected events for " + i);
+      do_throw(`Didn't see all the expected events for ${i}: Still expecting ${gExpectedEvents[i].map(([k]) => k)}`);
   }
   gExpectedEvents = {};
   if (gExpectedInstalls)
     Assert.equal(gExpectedInstalls.length, 0);
 }
 
 /**
  * A helper method to install an array of AddonInstall to completion and then
--- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
@@ -43,50 +43,47 @@ const ADDONS = [
 
       targetApplications: [{
         id: "xpcshell@tests.mozilla.org",
         minVersion: "1",
         maxVersion: "1"}],
     },
   },
   {
-    "install.rdf": {
-      id: "test_AddonRepository_2@tests.mozilla.org",
-      type: 4,
-      internalName: "test2/1.0",
+    "manifest.json": {
+      manifest_version: 2,
+      name: "XPI Add-on 2",
       version: "1.2",
-      bootstrap: true,
-      name: "XPI Add-on 2",
-
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "1"}],
+      applications: {
+        gecko: {
+          id: "test_AddonRepository_2@tests.mozilla.org",
+        },
+      },
+      theme: {},
     },
   },
   {
-    "install.rdf": {
-      id: "test_AddonRepository_3@tests.mozilla.org",
-      type: "4",
-      internalName: "test3/1.0",
+    "manifest.json": {
+      manifest_version: 2,
+      name: "XPI Add-on 3",
       version: "1.3",
-      bootstrap: true,
-      name: "XPI Add-on 3",
-
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "1"}],
+      applications: {
+        gecko: {
+          id: "test_AddonRepository_3@tests.mozilla.org",
+        },
+      },
+      theme: {},
+      icons: {32: "icon.png"},
     },
     "icon.png": "",
     "preview.png": "",
   },
 ];
 
-const ADDON_IDS = ADDONS.map(addon => addon["install.rdf"].id);
+const ADDON_IDS = ADDONS.map(addon => addon["install.rdf"] ? addon["install.rdf"].id : addon["manifest.json"].applications.gecko.id);
 const ADDON_FILES = ADDONS.map(addon => AddonTestUtils.createTempXPIFile(addon));
 
 const PREF_ADDON0_CACHE_ENABLED = "extensions." + ADDON_IDS[0] + ".getAddons.cache.enabled";
 const PREF_ADDON1_CACHE_ENABLED = "extensions." + ADDON_IDS[1] + ".getAddons.cache.enabled";
 
 // Properties of an individual add-on that should be checked
 // Note: size and updateDate are checked separately
 const ADDON_PROPERTIES = ["id", "type", "name", "version", "creator",
--- a/toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js
@@ -1,15 +1,17 @@
 const MANDATORY = ["id", "name"];
 const OPTIONAL = ["headerURL", "footerURL", "textcolor", "accentcolor",
                   "iconURL", "previewURL", "author", "description",
                   "homepageURL", "updateURL", "version"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
+const DEFAULT_THEME_ID = "default-theme@mozilla.org";
+
 function dummy(id) {
   return {
     id: id || Math.random().toString(),
     name: Math.random().toString(),
     headerURL: "http://lwttest.invalid/a.png",
     footerURL: "http://lwttest.invalid/b.png",
     textcolor: Math.random().toString(),
     accentcolor: Math.random().toString()
@@ -26,147 +28,147 @@ async function run_test() {
   startupManager();
 
   Services.prefs.setIntPref("lightweightThemes.maxUsedThemes", 8);
 
   let {LightweightThemeManager: ltm} = ChromeUtils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
 
   Assert.equal(typeof ltm, "object");
   Assert.equal(typeof ltm.usedThemes, "object");
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   ltm.previewTheme(dummy("preview0"));
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   ltm.previewTheme(dummy("preview1"));
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
   ltm.resetPreview();
 
   ltm.currentTheme = dummy("x0");
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.id, "x0");
   Assert.equal(ltm.usedThemes[0].id, "x0");
   Assert.equal(ltm.getUsedTheme("x0").id, "x0");
 
   ltm.previewTheme(dummy("preview0"));
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.id, "x0");
 
   ltm.resetPreview();
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.id, "x0");
 
   ltm.currentTheme = dummy("x1");
-  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.equal(ltm.usedThemes.length, 3);
   Assert.equal(ltm.currentTheme.id, "x1");
   Assert.equal(ltm.usedThemes[1].id, "x0");
 
   ltm.currentTheme = dummy("x2");
-  Assert.equal(ltm.usedThemes.length, 3);
+  Assert.equal(ltm.usedThemes.length, 4);
   Assert.equal(ltm.currentTheme.id, "x2");
   Assert.equal(ltm.usedThemes[1].id, "x1");
   Assert.equal(ltm.usedThemes[2].id, "x0");
 
   ltm.currentTheme = dummy("x3");
   ltm.currentTheme = dummy("x4");
   ltm.currentTheme = dummy("x5");
   ltm.currentTheme = dummy("x6");
   ltm.currentTheme = dummy("x7");
-  Assert.equal(ltm.usedThemes.length, 8);
+  Assert.equal(ltm.usedThemes.length, 9);
   Assert.equal(ltm.currentTheme.id, "x7");
   Assert.equal(ltm.usedThemes[1].id, "x6");
   Assert.equal(ltm.usedThemes[7].id, "x0");
 
   ltm.currentTheme = dummy("x8");
-  Assert.equal(ltm.usedThemes.length, 8);
+  Assert.equal(ltm.usedThemes.length, 9);
   Assert.equal(ltm.currentTheme.id, "x8");
   Assert.equal(ltm.usedThemes[1].id, "x7");
   Assert.equal(ltm.usedThemes[7].id, "x1");
   Assert.equal(ltm.getUsedTheme("x0"), null);
 
   ltm.forgetUsedTheme("nonexistent");
-  Assert.equal(ltm.usedThemes.length, 8);
-  Assert.notEqual(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 9);
+  Assert.notEqual(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   ltm.forgetUsedTheme("x8");
-  Assert.equal(ltm.usedThemes.length, 7);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 8);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
   Assert.equal(ltm.usedThemes[0].id, "x7");
   Assert.equal(ltm.usedThemes[6].id, "x1");
 
   ltm.forgetUsedTheme("x7");
   ltm.forgetUsedTheme("x6");
   ltm.forgetUsedTheme("x5");
   ltm.forgetUsedTheme("x4");
   ltm.forgetUsedTheme("x3");
-  Assert.equal(ltm.usedThemes.length, 2);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 3);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
   Assert.equal(ltm.usedThemes[0].id, "x2");
   Assert.equal(ltm.usedThemes[1].id, "x1");
 
   ltm.currentTheme = dummy("x1");
-  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.equal(ltm.usedThemes.length, 3);
   Assert.equal(ltm.currentTheme.id, "x1");
   Assert.equal(ltm.usedThemes[0].id, "x1");
   Assert.equal(ltm.usedThemes[1].id, "x2");
 
   ltm.currentTheme = dummy("x2");
-  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.equal(ltm.usedThemes.length, 3);
   Assert.equal(ltm.currentTheme.id, "x2");
   Assert.equal(ltm.usedThemes[0].id, "x2");
   Assert.equal(ltm.usedThemes[1].id, "x1");
 
   ltm.currentTheme = ltm.getUsedTheme("x1");
-  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.equal(ltm.usedThemes.length, 3);
   Assert.equal(ltm.currentTheme.id, "x1");
   Assert.equal(ltm.usedThemes[0].id, "x1");
   Assert.equal(ltm.usedThemes[1].id, "x2");
 
   ltm.forgetUsedTheme("x1");
   ltm.forgetUsedTheme("x2");
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   // Use chinese name to test utf-8, for bug #541943
   var chineseTheme = dummy("chinese0");
   chineseTheme.name = "笢恅0";
   chineseTheme.description = "笢恅1";
   ltm.currentTheme = chineseTheme;
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.name, "笢恅0");
   Assert.equal(ltm.currentTheme.description, "笢恅1");
   Assert.equal(ltm.usedThemes[0].name, "笢恅0");
   Assert.equal(ltm.usedThemes[0].description, "笢恅1");
   Assert.equal(ltm.getUsedTheme("chinese0").name, "笢恅0");
   Assert.equal(ltm.getUsedTheme("chinese0").description, "笢恅1");
 
   // This name used to break the usedTheme JSON causing all LWTs to be lost
   var chineseTheme1 = dummy("chinese1");
   chineseTheme1.name = "眵昜湮桵蔗坌~郔乾";
   chineseTheme1.description = "眵昜湮桵蔗坌~郔乾";
   ltm.currentTheme = chineseTheme1;
-  Assert.notEqual(ltm.currentTheme, null);
-  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.notEqual(ltm.currentTheme.id, DEFAULT_THEME_ID);
+  Assert.equal(ltm.usedThemes.length, 3);
   Assert.equal(ltm.currentTheme.name, "眵昜湮桵蔗坌~郔乾");
   Assert.equal(ltm.currentTheme.description, "眵昜湮桵蔗坌~郔乾");
   Assert.equal(ltm.usedThemes[1].name, "笢恅0");
   Assert.equal(ltm.usedThemes[1].description, "笢恅1");
   Assert.equal(ltm.usedThemes[0].name, "眵昜湮桵蔗坌~郔乾");
   Assert.equal(ltm.usedThemes[0].description, "眵昜湮桵蔗坌~郔乾");
 
   ltm.forgetUsedTheme("chinese0");
-  Assert.equal(ltm.usedThemes.length, 1);
-  Assert.notEqual(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.notEqual(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   ltm.forgetUsedTheme("chinese1");
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   Assert.equal(ltm.parseTheme("invalid json"), null);
   Assert.equal(ltm.parseTheme('"json string"'), null);
 
   function roundtrip(data, secure) {
     return ltm.parseTheme(JSON.stringify(data),
                           "http" + (secure ? "s" : "") + "://lwttest.invalid/");
   }
@@ -295,142 +297,142 @@ async function run_test() {
   });
 
   roundtripSet(urls(OPTIONAL), function(theme, prop) {
     theme[prop] = "ftp://lwttest.invalid/" + Math.random().toString();
   }, function(after, prop) {
     Assert.equal(typeof after[prop], "undefined");
   });
 
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   data = dummy();
   delete data.name;
   try {
     ltm.currentTheme = data;
     do_throw("Should have rejected a theme with no name");
   } catch (e) {
     // Expected exception
   }
 
   // Sanitize themes with a bad headerURL
   data = dummy();
   data.headerURL = "foo";
   ltm.currentTheme = data;
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.headerURL, undefined);
   ltm.forgetUsedTheme(ltm.currentTheme.id);
-  Assert.equal(ltm.usedThemes.length, 0);
+  Assert.equal(ltm.usedThemes.length, 1);
 
   // Sanitize themes with a non-http(s) headerURL
   data = dummy();
   data.headerURL = "ftp://lwtest.invalid/test.png";
   ltm.currentTheme = data;
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.headerURL, undefined);
   ltm.forgetUsedTheme(ltm.currentTheme.id);
-  Assert.equal(ltm.usedThemes.length, 0);
+  Assert.equal(ltm.usedThemes.length, 1);
 
   // Sanitize themes with a non-http(s) headerURL
   data = dummy();
   data.headerURL = "file:///test.png";
   ltm.currentTheme = data;
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.headerURL, undefined);
   ltm.forgetUsedTheme(ltm.currentTheme.id);
-  Assert.equal(ltm.usedThemes.length, 0);
+  Assert.equal(ltm.usedThemes.length, 1);
 
   data = dummy();
   data.updateURL = "file:///test.json";
   ltm.setLocalTheme(data);
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.updateURL, undefined);
   ltm.forgetUsedTheme(ltm.currentTheme.id);
-  Assert.equal(ltm.usedThemes.length, 0);
+  Assert.equal(ltm.usedThemes.length, 1);
 
   data = dummy();
   data.headerURL = "file:///test.png";
   ltm.setLocalTheme(data);
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.headerURL, "file:///test.png");
   ltm.forgetUsedTheme(ltm.currentTheme.id);
-  Assert.equal(ltm.usedThemes.length, 0);
+  Assert.equal(ltm.usedThemes.length, 1);
 
   data = dummy();
   data.headerURL = "ftp://lwtest.invalid/test.png";
   ltm.setLocalTheme(data);
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   Assert.equal(ltm.currentTheme.updateURL, undefined);
   ltm.forgetUsedTheme(ltm.currentTheme.id);
-  Assert.equal(ltm.usedThemes.length, 0);
+  Assert.equal(ltm.usedThemes.length, 1);
 
   data = dummy();
   delete data.id;
   try {
     ltm.currentTheme = data;
     do_throw("Should have rejected a theme with no ID");
   } catch (e) {
     // Expected exception
   }
 
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   // Force the theme into the prefs anyway
   let themes = [data];
   Services.prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes));
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
 
   // This should silently drop the bad theme.
   ltm.currentTheme = dummy();
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   ltm.forgetUsedTheme(ltm.currentTheme.id);
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   // Add one broken and some working.
   themes = [data, dummy("x1"), dummy("x2")];
   Services.prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes));
-  Assert.equal(ltm.usedThemes.length, 3);
+  Assert.equal(ltm.usedThemes.length, 4);
 
   // Switching to an existing theme should drop the bad theme.
   ltm.currentTheme = ltm.getUsedTheme("x1");
-  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.equal(ltm.usedThemes.length, 3);
   ltm.forgetUsedTheme("x1");
   ltm.forgetUsedTheme("x2");
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   Services.prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes));
-  Assert.equal(ltm.usedThemes.length, 3);
+  Assert.equal(ltm.usedThemes.length, 4);
 
   // Forgetting an existing theme should drop the bad theme.
   ltm.forgetUsedTheme("x1");
-  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.usedThemes.length, 2);
   ltm.forgetUsedTheme("x2");
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   // Test whether a JSON set with setCharPref can be retrieved with usedThemes
   ltm.currentTheme = dummy("x0");
   ltm.currentTheme = dummy("x1");
   Services.prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(ltm.usedThemes));
-  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.equal(ltm.usedThemes.length, 4);
   Assert.equal(ltm.currentTheme.id, "x1");
   Assert.equal(ltm.usedThemes[1].id, "x0");
   Assert.equal(ltm.usedThemes[0].id, "x1");
 
   ltm.forgetUsedTheme("x0");
-  Assert.equal(ltm.usedThemes.length, 1);
-  Assert.notEqual(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.notEqual(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   ltm.forgetUsedTheme("x1");
-  Assert.equal(ltm.usedThemes.length, 0);
-  Assert.equal(ltm.currentTheme, null);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.id, DEFAULT_THEME_ID);
 
   Services.prefs.clearUserPref("lightweightThemes.maxUsedThemes");
 
   ltm.currentTheme = dummy("x1");
   ltm.currentTheme = dummy("x2");
   ltm.currentTheme = dummy("x3");
   ltm.currentTheme = dummy("x4");
   ltm.currentTheme = dummy("x5");
@@ -455,26 +457,26 @@ async function run_test() {
   ltm.currentTheme = dummy("x24");
   ltm.currentTheme = dummy("x25");
   ltm.currentTheme = dummy("x26");
   ltm.currentTheme = dummy("x27");
   ltm.currentTheme = dummy("x28");
   ltm.currentTheme = dummy("x29");
   ltm.currentTheme = dummy("x30");
 
-  Assert.equal(ltm.usedThemes.length, 30);
+  Assert.equal(ltm.usedThemes.length, 31);
 
   ltm.currentTheme = dummy("x31");
 
-  Assert.equal(ltm.usedThemes.length, 30);
+  Assert.equal(ltm.usedThemes.length, 31);
   Assert.equal(ltm.getUsedTheme("x1"), null);
 
   Services.prefs.setIntPref("lightweightThemes.maxUsedThemes", 15);
 
-  Assert.equal(ltm.usedThemes.length, 15);
+  Assert.equal(ltm.usedThemes.length, 16);
 
   Services.prefs.setIntPref("lightweightThemes.maxUsedThemes", 32);
 
   ltm.currentTheme = dummy("x1");
   ltm.currentTheme = dummy("x2");
   ltm.currentTheme = dummy("x3");
   ltm.currentTheme = dummy("x4");
   ltm.currentTheme = dummy("x5");
@@ -487,45 +489,45 @@ async function run_test() {
   ltm.currentTheme = dummy("x12");
   ltm.currentTheme = dummy("x13");
   ltm.currentTheme = dummy("x14");
   ltm.currentTheme = dummy("x15");
   ltm.currentTheme = dummy("x16");
 
   ltm.currentTheme = dummy("x32");
 
-  Assert.equal(ltm.usedThemes.length, 32);
+  Assert.equal(ltm.usedThemes.length, 33);
 
   ltm.currentTheme = dummy("x33");
 
-  Assert.equal(ltm.usedThemes.length, 32);
+  Assert.equal(ltm.usedThemes.length, 33);
 
   Services.prefs.clearUserPref("lightweightThemes.maxUsedThemes");
 
-  Assert.equal(ltm.usedThemes.length, 30);
+  Assert.equal(ltm.usedThemes.length, 31);
 
   let usedThemes = ltm.usedThemes;
   for (let theme of usedThemes) {
     ltm.forgetUsedTheme(theme.id);
   }
 
   // Check builtInTheme functionality for Bug 1094821
   Assert.equal(ltm._builtInThemes.toString(), "[object Map]");
-  Assert.equal([...ltm._builtInThemes.entries()].length, 0);
-  Assert.equal(ltm.usedThemes.length, 0);
+  Assert.equal([...ltm._builtInThemes.entries()].length, 1);
+  Assert.equal(ltm.usedThemes.length, 1);
 
   ltm.addBuiltInTheme(dummy("builtInTheme0"));
-  Assert.equal([...ltm._builtInThemes].length, 1);
-  Assert.equal(ltm.usedThemes.length, 1);
-  Assert.equal(ltm.usedThemes[0].id, "builtInTheme0");
+  Assert.equal([...ltm._builtInThemes].length, 2);
+  Assert.equal(ltm.usedThemes.length, 2);
+  Assert.equal(ltm.usedThemes[1].id, "builtInTheme0");
 
   ltm.addBuiltInTheme(dummy("builtInTheme1"));
-  Assert.equal([...ltm._builtInThemes].length, 2);
-  Assert.equal(ltm.usedThemes.length, 2);
-  Assert.equal(ltm.usedThemes[1].id, "builtInTheme1");
+  Assert.equal([...ltm._builtInThemes].length, 3);
+  Assert.equal(ltm.usedThemes.length, 3);
+  Assert.equal(ltm.usedThemes[2].id, "builtInTheme1");
 
   // Clear all and then re-add
   ltm.clearBuiltInThemes();
   Assert.equal([...ltm._builtInThemes].length, 0);
   Assert.equal(ltm.usedThemes.length, 0);
 
   ltm.addBuiltInTheme(dummy("builtInTheme0"));
   ltm.addBuiltInTheme(dummy("builtInTheme1"));
--- a/toolkit/mozapps/extensions/test/xpcshell/test_addonStartup.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_addonStartup.js
@@ -1,28 +1,15 @@
 "use strict";
 
 add_task(async function test_XPIStates_invalid_paths() {
   let {path} = gAddonStartup;
 
   let startupDatasets = [
     {
-      "app-global": {
-        "addons": {
-          "{972ce4c6-7e08-4474-a285-3208198ce6fd}": {
-            "enabled": true,
-            "lastModifiedTime": 1,
-            "path": "{972ce4c6-7e08-4474-a285-3208198ce6fd}",
-            "type": "theme",
-            "version": "55.0a1",
-          }
-        },
-        "checkStartupModifications": true,
-        "path": "c:\\Program Files\\Mozilla Firefox\\extensions",
-      },
       "app-profile": {
         "addons": {
           "xpcshell-something-or-other@mozilla.org": {
             "bootstrapped": true,
             "dependencies": [],
             "enabled": true,
             "hasEmbeddedWebExtension": false,
             "lastModifiedTime": 1,
@@ -30,29 +17,16 @@ add_task(async function test_XPIStates_i
             "version": "0.0.0",
           },
         },
         "checkStartupModifications": true,
         "path": "/home/xpcshell/.mozilla/firefox/default/extensions",
       },
     },
     {
-      "app-global": {
-        "addons": {
-          "{972ce4c6-7e08-4474-a285-3208198ce6fd}": {
-            "enabled": true,
-            "lastModifiedTime": 1,
-            "path": "{972ce4c6-7e08-4474-a285-3208198ce6fd}",
-            "type": "theme",
-            "version": "55.0a1",
-          }
-        },
-        "checkStartupModifications": true,
-        "path": "c:\\Program Files\\Mozilla Firefox\\extensions",
-      },
       "app-profile": {
         "addons": {
           "xpcshell-something-or-other@mozilla.org": {
             "bootstrapped": true,
             "dependencies": [],
             "enabled": true,
             "hasEmbeddedWebExtension": false,
             "lastModifiedTime": 1,
--- a/toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js
@@ -26,17 +26,17 @@ function run_test() {
 function end_test() {
   do_test_finished();
 }
 
 // Verify that with no add-ons installed the background update notifications get
 // called
 async function run_test_1() {
   let aAddons = await AddonManager.getAddonsByTypes(["extension", "theme", "locale"]);
-  Assert.equal(aAddons.length, 0);
+  Assert.equal(aAddons.length, 1);
 
   Services.obs.addObserver(function observer() {
     Services.obs.removeObserver(observer, "addons-background-update-complete");
 
     executeSoon(run_test_2);
   }, "addons-background-update-complete");
 
   // Trigger the background update timer handler
--- a/toolkit/mozapps/extensions/test/xpcshell/test_badschema.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_badschema.js
@@ -178,26 +178,26 @@ const ADDONS = {
       appDisabled: false,
       pendingOperations: 0,
     },
     afterCorruption: {},
     afterSecondRestart: {},
   },
 
   "theme1@tests.mozilla.org": {
-    "install.rdf": {
-      id: "theme1@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
+      manifest_version: 2,
       name: "Theme 1",
-      internalName: "classic/1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2"
-      }]
+      version: "1.0",
+      theme: { images: { headerURL: "example.png" } },
+      applications: {
+        gecko: {
+          id: "theme1@tests.mozilla.org",
+        },
+      },
     },
     desiredValues: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
     afterCorruption: {},
--- a/toolkit/mozapps/extensions/test/xpcshell/test_manifest.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_manifest.js
@@ -597,39 +597,16 @@ const ADDONS = [
         maxVersion: "1"
       }],
       name: "Test Addon 26"
     },
     extraFiles: {"options.xul": ""},
     expected: null,
   },
 
-  // Theme manifests should ignore aboutURL and optionsURL.
-  {
-    "install.rdf": {
-      id: "bug371495@tests.mozilla.org",
-      version: "1.0",
-      type: "4",
-      internalName: "test/1.0",
-      optionsURL: "chrome://foo/content/bar.xul",
-      aboutURL: "chrome://foo/content/bar.xul",
-      name: "Test theme",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "1",
-      }],
-    },
-
-    expected: {
-      aboutURL: null,
-      optionsURL: null,
-    }
-  },
-
   // Tests compatibility based on target platforms.
 
   // No targetPlatforms so should be compatible
   {
     "install.rdf": {
       id: "tp-addon1@tests.mozilla.org",
       version: "1.0",
       bootstrap: true,
--- a/toolkit/mozapps/extensions/test/xpcshell/test_strictcompatibility.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_strictcompatibility.js
@@ -42,35 +42,16 @@ const ADDONS = {
       }]
     },
     expected: {
       strictCompatibility: false,
     },
     compatible: [false, true,  false, true],
   },
 
-  // Theme - always uses strict compatibility, so is always incompatible
-  "addon3@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon3@tests.mozilla.org",
-      version: "1.0",
-      name: "Test 3",
-      internalName: "test-theme-3",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "0.8",
-        maxVersion: "0.9"
-      }]
-    },
-    expected: {
-      strictCompatibility: true,
-    },
-    compatible: [false, false, false, false],
-  },
-
   // Opt-in to strict compatibility - always incompatible
   "addon4@tests.mozilla.org": {
     "install.rdf": {
       id: "addon4@tests.mozilla.org",
       version: "1.0",
       name: "Test 4",
       bootstrap: true,
       strictCompatibility: true,
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_theme.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_theme.js
@@ -3,21 +3,22 @@
 /**
  * This file contains test for 'theme' type WebExtension addons. Tests focus mostly
  * on interoperability between the different theme formats (XUL and LWT) and
  * Addon Manager integration.
  *
  * Coverage may overlap with other tests in this folder.
  */
 
-const {LightweightThemeManager} = ChromeUtils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
+ChromeUtils.defineModuleGetter(this, "LightweightThemeManager",
+                               "resource://gre/modules/LightweightThemeManager.jsm");
 const THEME_IDS = [
   "theme3@tests.mozilla.org",
   "theme2@personas.mozilla.org",
-  "default@tests.mozilla.org"
+  "default-theme@mozilla.org",
 ];
 const DEFAULT_THEME = THEME_IDS[2];
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 // We remember the last/ currently active theme for tracking events.
 var gActiveTheme = null;
@@ -32,29 +33,16 @@ add_task(async function setup_to_default
     version: "1.0",
     theme: { images: { headerURL: "example.png" } },
     applications: {
       gecko: {
         id: THEME_IDS[0]
       }
     }
   }, profileDir);
-  // We need a default theme for some of these things to work but we have hidden
-  // the one in the application directory.
-  writeInstallRDFForExtension({
-    id: DEFAULT_THEME,
-    version: "1.0",
-    name: "Default",
-    internalName: "classic/1.0",
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "2"
-    }]
-  }, profileDir);
 
   startupManager();
 
   // We can add an LWT only after the Addon Manager was started.
   LightweightThemeManager.currentTheme = {
     id: THEME_IDS[1].substr(0, THEME_IDS[1].indexOf("@")),
     version: "1",
     name: "Bling",
--- a/toolkit/themes/linux/mozapps/jar.mn
+++ b/toolkit/themes/linux/mozapps/jar.mn
@@ -3,14 +3,8 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
 #include ../../shared/mozapps.inc.mn
 * skin/classic/mozapps/extensions/extensions.css           (extensions/extensions.css)
   skin/classic/mozapps/extensions/heart.png                (extensions/heart.png)
   skin/classic/mozapps/profile/profileicon.png             (profile/profileicon.png)
   skin/classic/mozapps/update/updates.css                  (update/updates.css)
-
-#if MOZ_BUILD_APP == browser
-[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#endif
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -78,14 +78,8 @@ toolkit.jar:
   skin/classic/global/icons/question-64.png                          (icons/question-64.png)
   skin/classic/global/icons/sslWarning.png                           (icons/sslWarning.png)
 * skin/classic/global/in-content/common.css                          (in-content/common.css)
 * skin/classic/global/in-content/info-pages.css                      (in-content/info-pages.css)
   skin/classic/global/tree/arrow-disclosure.svg                      (tree/arrow-disclosure.svg)
   skin/classic/global/tree/columnpicker.gif                          (tree/columnpicker.gif)
   skin/classic/global/tree/folder.png                                (tree/folder.png)
   skin/classic/global/tree/folder@2x.png                             (tree/folder@2x.png)
-
-#if MOZ_BUILD_APP == browser
-[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#endif
--- a/toolkit/themes/osx/mozapps/jar.mn
+++ b/toolkit/themes/osx/mozapps/jar.mn
@@ -18,14 +18,8 @@ toolkit.jar:
   skin/classic/mozapps/plugins/pluginHelp-16.png                  (plugins/pluginHelp-16.png)
   skin/classic/mozapps/profile/profileicon.png                    (profile/profileicon.png)
   skin/classic/mozapps/profile/profileSelection.css               (profile/profileSelection.css)
   skin/classic/mozapps/profile/profileicon-selected.png           (profile/profileicon-selected.png)
   skin/classic/mozapps/update/buttons.png                         (update/buttons.png)
 * skin/classic/mozapps/update/updates.css                         (update/updates.css)
   skin/classic/mozapps/xpinstall/xpinstallConfirm.css             (extensions/xpinstallConfirm.css)
   skin/classic/mozapps/handling/handling.css                      (handling/handling.css)
-
-#if MOZ_BUILD_APP == browser
-[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#endif
--- a/toolkit/themes/shared/non-mac.jar.inc.mn
+++ b/toolkit/themes/shared/non-mac.jar.inc.mn
@@ -47,14 +47,9 @@
   skin/classic/mozapps/extensions/cancel.png                 (../../windows/mozapps/extensions/cancel.png)
   skin/classic/mozapps/extensions/eula.css                   (../../windows/mozapps/extensions/eula.css)
   skin/classic/mozapps/handling/handling.css                 (../../windows/mozapps/handling/handling.css)
   skin/classic/mozapps/plugins/pluginHelp-16.png             (../../windows/mozapps/plugins/pluginHelp-16.png)
   skin/classic/mozapps/profile/profileSelection.css          (../../windows/mozapps/profile/profileSelection.css)
   skin/classic/mozapps/update/downloadButtons.png            (../../windows/mozapps/update/downloadButtons.png)
 * skin/classic/mozapps/xpinstall/xpinstallConfirm.css        (../../windows/mozapps/extensions/xpinstallConfirm.css)
 
-#if MOZ_BUILD_APP == browser
-[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#endif
 % override chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png       chrome://mozapps/skin/extensions/extensionGeneric.svg
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -56,22 +56,16 @@ toolkit.jar:
   skin/classic/global/icons/Warning.png                    (icons/Warning.png)
   skin/classic/global/icons/warning-large.png              (icons/warning-large.png)
   skin/classic/global/icons/windowControls.png             (icons/windowControls.png)
 * skin/classic/global/in-content/common.css                (in-content/common.css)
 * skin/classic/global/in-content/info-pages.css            (in-content/info-pages.css)
   skin/classic/global/tree/twisty.svg                      (tree/twisty.svg)
   skin/classic/global/tree/twisty-preWin10.svg             (tree/twisty-preWin10.svg)
 
-#if MOZ_BUILD_APP == browser
-[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#endif
-
 % override chrome://global/skin/tree/twisty.svg#clsd              chrome://global/skin/tree/twisty-preWin10.svg#clsd           osversion<=6.3
 % override chrome://global/skin/tree/twisty.svg#clsd-rtl          chrome://global/skin/tree/twisty-preWin10.svg#clsd-rtl       osversion<=6.3
 % override chrome://global/skin/tree/twisty.svg#clsd-hover        chrome://global/skin/tree/twisty-preWin10.svg#clsd-hover     osversion<=6.3
 % override chrome://global/skin/tree/twisty.svg#clsd-hover-rtl    chrome://global/skin/tree/twisty-preWin10.svg#clsd-hover-rtl osversion<=6.3
 % override chrome://global/skin/tree/twisty.svg#open              chrome://global/skin/tree/twisty-preWin10.svg#open           osversion<=6.3
 % override chrome://global/skin/tree/twisty.svg#open-rtl          chrome://global/skin/tree/twisty-preWin10.svg#open-rtl       osversion<=6.3
 % override chrome://global/skin/tree/twisty.svg#open-hover        chrome://global/skin/tree/twisty-preWin10.svg#open-hover     osversion<=6.3
 % override chrome://global/skin/tree/twisty.svg#open-hover-rtl    chrome://global/skin/tree/twisty-preWin10.svg#open-hover-rtl osversion<=6.3
--- a/toolkit/themes/windows/mozapps/jar.mn
+++ b/toolkit/themes/windows/mozapps/jar.mn
@@ -3,14 +3,8 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
 #include ../../shared/mozapps.inc.mn
 * skin/classic/mozapps/extensions/extensions.css             (extensions/extensions.css)
   skin/classic/mozapps/extensions/heart.png                  (extensions/heart.png)
   skin/classic/mozapps/profile/profileicon.png               (profile/profileicon.png)
   skin/classic/mozapps/update/updates.css                    (update/updates.css)
-
-#if MOZ_BUILD_APP == browser
-[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES
-[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
-#endif