Bug 1462470 - Part 2 - Alert about trackers when Tracking Protection is off in the identity popup. r=paolo draft
authorJohann Hofmann <jhofmann@mozilla.com>
Thu, 24 May 2018 13:12:30 +0200
changeset 805347 17dce2365fe064e659cea208fdb2d6b0d7626792
parent 805346 d5d2a8a28fb551b0d844af499621af25f4485789
child 805348 3b5a1b67409f41c74194f7b72b0de83118e450cd
push id112640
push userjhofmann@mozilla.com
push dateThu, 07 Jun 2018 18:37:45 +0000
reviewerspaolo
bugs1462470
milestone62.0a1
Bug 1462470 - Part 2 - Alert about trackers when Tracking Protection is off in the identity popup. r=paolo This commit changes the tracking protection UI to always be present in the identity popup (control center) UI. Following the UI spec in https://mozilla.invisionapp.com/share/RSIY1B8GMC2#/screens/297824891, we are now warning about trackers even when TP is disabled and alter the button that shows up in this case to open the TP settings in about:preferences. MozReview-Commit-ID: 6g8rzWVRaua
browser/base/content/browser-trackingprotection.js
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_trackingUI_2.js
browser/components/controlcenter/content/panel.inc.xul
browser/components/customizableui/content/panelUI.inc.xul
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/osx/controlcenter/panel.css
browser/themes/shared/controlcenter/panel.inc.css
toolkit/modules/PrivateBrowsingUtils.jsm
--- a/browser/base/content/browser-trackingprotection.js
+++ b/browser/base/content/browser-trackingprotection.js
@@ -10,16 +10,23 @@ var TrackingProtection = {
   enabledGlobally: false,
   enabledInPrivateWindows: false,
   container: null,
   content: null,
   icon: null,
   activeTooltipText: null,
   disabledTooltipText: null,
 
+  get _baseURIForChannelClassifier() {
+    // Convert document URI into the format used by
+    // nsChannelClassifier::ShouldEnableTrackingProtection.
+    // Any scheme turned into https is correct.
+    return Services.io.newURI("https://" + gBrowser.selectedBrowser.currentURI.hostPort);
+  },
+
   init() {
     let $ = selector => document.querySelector(selector);
     this.container = $("#tracking-protection-container");
     this.content = $("#tracking-protection-content");
     this.icon = $("#tracking-protection-icon");
     this.broadcaster = $("#trackingProtectionBroadcaster");
 
     this.enableTooltip =
@@ -62,26 +69,27 @@ var TrackingProtection = {
   onGlobalToggleCommand() {
     if (PrivateBrowsingUtils.isWindowPrivate(window)) {
       Services.prefs.setBoolPref(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, !this.enabledInPrivateWindows);
     } else {
       Services.prefs.setBoolPref(this.PREF_ENABLED_GLOBALLY, !this.enabledGlobally);
     }
   },
 
-  openPreferences() {
-    openPreferences("privacy-trackingprotection", { origin: "appMenu-trackingprotection" });
+  openPreferences(origin) {
+    openPreferences("privacy-trackingprotection", { origin });
   },
 
   updateEnabled() {
     this.enabledGlobally =
       Services.prefs.getBoolPref(this.PREF_ENABLED_GLOBALLY);
     this.enabledInPrivateWindows =
       Services.prefs.getBoolPref(this.PREF_ENABLED_IN_PRIVATE_WINDOWS);
-    this.container.hidden = !this.enabled;
+
+    this.content.setAttribute("enabled", this.enabled);
 
     if (PrivateBrowsingUtils.isWindowPrivate(window)) {
       this.broadcaster.setAttribute("enabled", this.enabledInPrivateWindows);
       this.broadcaster.setAttribute("aria-pressed", this.enabledInPrivateWindows);
       this.broadcaster.setAttribute("tooltiptext", this.enabledInPrivateWindows ?
         this.disableTooltipPB : this.enableTooltipPB);
     } else {
       this.broadcaster.setAttribute("enabled", this.enabledGlobally);
@@ -115,103 +123,127 @@ var TrackingProtection = {
   shieldHistogramAdd(value) {
     if (PrivateBrowsingUtils.isWindowPrivate(window)) {
       return;
     }
     Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD").add(value);
   },
 
   onSecurityChange(state, isSimulated) {
-    if (!this.enabled) {
-      return;
-    }
-
     // Only animate the shield if the event was not fired directly from
     // the tabbrowser (due to a browser change).
     if (isSimulated) {
       this.icon.removeAttribute("animate");
     } else {
       this.icon.setAttribute("animate", "true");
     }
 
     let isBlocking = state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT;
     let isAllowing = state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT;
 
-    if (isBlocking) {
+    if (isBlocking && this.enabled) {
       this.icon.setAttribute("tooltiptext", this.activeTooltipText);
       this.icon.setAttribute("state", "blocked-tracking-content");
       this.content.setAttribute("state", "blocked-tracking-content");
+      this.content.removeAttribute("hasException");
 
       // Open the tracking protection introduction panel, if applicable.
       if (this.enabledGlobally) {
         let introCount = Services.prefs.getIntPref("privacy.trackingprotection.introCount");
         if (introCount < TrackingProtection.MAX_INTROS) {
           Services.prefs.setIntPref("privacy.trackingprotection.introCount", ++introCount);
           Services.prefs.savePrefFile(null);
           this.showIntroPanel();
         }
       }
 
       this.shieldHistogramAdd(2);
     } else if (isAllowing) {
-      this.icon.setAttribute("tooltiptext", this.disabledTooltipText);
-      this.icon.setAttribute("state", "loaded-tracking-content");
+      // Check whether the user has added an exception for this site.
+      let hasException = false;
+      if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
+        hasException = PrivateBrowsingUtils.existsInTrackingAllowlist(this._baseURIForChannelClassifier);
+      } else {
+        hasException = Services.perms.testExactPermission(this._baseURIForChannelClassifier,
+          "trackingprotection") == Services.perms.ALLOW_ACTION;
+      }
+
+      if (hasException) {
+        this.content.setAttribute("hasException", "true");
+      } else {
+        this.content.removeAttribute("hasException");
+      }
+
+      // Only show the shield when TP is enabled for now.
+      if (this.enabled) {
+        this.icon.setAttribute("tooltiptext", this.disabledTooltipText);
+        this.icon.setAttribute("state", "loaded-tracking-content");
+        this.shieldHistogramAdd(1);
+      } else {
+        this.icon.removeAttribute("tooltiptext");
+        this.icon.removeAttribute("state");
+        this.shieldHistogramAdd(0);
+      }
+
+      // Warn in the control center even with TP disabled.
       this.content.setAttribute("state", "loaded-tracking-content");
-
-      this.shieldHistogramAdd(1);
     } else {
       this.icon.removeAttribute("tooltiptext");
       this.icon.removeAttribute("state");
       this.content.removeAttribute("state");
+      this.content.removeAttribute("hasException");
 
       // We didn't show the shield
       this.shieldHistogramAdd(0);
     }
 
     // Telemetry for state change.
     this.eventsHistogramAdd(0);
   },
 
   disableForCurrentPage() {
-    // Convert document URI into the format used by
-    // nsChannelClassifier::ShouldEnableTrackingProtection.
-    // Any scheme turned into https is correct.
-    let normalizedUrl = Services.io.newURI(
-      "https://" + gBrowser.selectedBrowser.currentURI.hostPort);
+    let baseURI = this._baseURIForChannelClassifier;
 
     // Add the current host in the 'trackingprotection' consumer of
     // the permission manager using a normalized URI. This effectively
     // places this host on the tracking protection allowlist.
     if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
-      PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl);
+      PrivateBrowsingUtils.addToTrackingAllowlist(baseURI);
     } else {
-      Services.perms.add(normalizedUrl,
+      Services.perms.add(baseURI,
         "trackingprotection", Services.perms.ALLOW_ACTION);
     }
 
     // Telemetry for disable protection.
     this.eventsHistogramAdd(1);
 
     // Hide the control center.
     document.getElementById("identity-popup").hidePopup();
 
     BrowserReload();
   },
 
   enableForCurrentPage() {
+    // If users are not clicking this link to unblock a specific exception,
+    // open the privacy settings to allow users to turn TP on globally. We might
+    // change this button to allow globally toggling the pref in the future.
+    if (!this.enabled) {
+      this.openPreferences("identityPopup-TP-action");
+      return;
+    }
+
     // Remove the current host from the 'trackingprotection' consumer
     // of the permission manager. This effectively removes this host
     // from the tracking protection allowlist.
-    let normalizedUrl = Services.io.newURI(
-      "https://" + gBrowser.selectedBrowser.currentURI.hostPort);
+    let baseURI = this._baseURIForChannelClassifier;
 
     if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
-      PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl);
+      PrivateBrowsingUtils.removeFromTrackingAllowlist(baseURI);
     } else {
-      Services.perms.remove(normalizedUrl, "trackingprotection");
+      Services.perms.remove(baseURI, "trackingprotection");
     }
 
     // Telemetry for enable protection.
     this.eventsHistogramAdd(2);
 
     // Hide the control center.
     document.getElementById("identity-popup").hidePopup();
 
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -456,22 +456,16 @@ support-files =
 run-if = e10s
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_trackingUI_1.js]
 tags = trackingprotection
 support-files =
   trackingPage.html
   benignPage.html
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-[browser_trackingUI_2.js]
-tags = trackingprotection
-support-files =
-  trackingPage.html
-  benignPage.html
-# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_trackingUI_3.js]
 tags = trackingprotection
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_trackingUI_4.js]
 tags = trackingprotection
 support-files =
   trackingPage.html
   benignPage.html
deleted file mode 100644
--- a/browser/base/content/test/general/browser_trackingUI_2.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Test that the Tracking Protection section is never visible in the
- * Control Center when the feature is off.
- * See also Bugs 1175327, 1043801, 1178985.
- */
-
-const PREF = "privacy.trackingprotection.enabled";
-const PB_PREF = "privacy.trackingprotection.pbmode.enabled";
-const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
-const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
-var TrackingProtection = null;
-var tabbrowser = null;
-
-var {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
-
-registerCleanupFunction(function() {
-  TrackingProtection = tabbrowser = null;
-  UrlClassifierTestUtils.cleanupTestTrackers();
-  Services.prefs.clearUserPref(PREF);
-  Services.prefs.clearUserPref(PB_PREF);
-  while (gBrowser.tabs.length > 1) {
-    gBrowser.removeCurrentTab();
-  }
-});
-
-function hidden(el) {
-  let win = el.ownerGlobal;
-  let display = win.getComputedStyle(el).getPropertyValue("display", null);
-  let opacity = win.getComputedStyle(el).getPropertyValue("opacity", null);
-
-  return display === "none" || opacity === "0";
-}
-
-add_task(async function testNormalBrowsing() {
-  await UrlClassifierTestUtils.addTestTrackers();
-
-  tabbrowser = gBrowser;
-  let {gIdentityHandler} = tabbrowser.ownerGlobal;
-  let tab = tabbrowser.selectedTab = tabbrowser.addTab();
-
-  TrackingProtection = tabbrowser.ownerGlobal.TrackingProtection;
-  ok(TrackingProtection, "TP is attached to the browser window");
-  is(TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
-    "TP.enabled is based on the original pref value");
-
-  Services.prefs.setBoolPref(PREF, true);
-  ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
-
-  Services.prefs.setBoolPref(PREF, false);
-  ok(!TrackingProtection.enabled, "TP is disabled after setting the pref");
-
-  info("Load a test page containing tracking elements");
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
-  gIdentityHandler._identityBox.click();
-  ok(hidden(TrackingProtection.container), "The container is hidden");
-  gIdentityHandler._identityPopup.hidden = true;
-
-  info("Load a test page not containing tracking elements");
-  await promiseTabLoadEvent(tab, BENIGN_PAGE);
-  gIdentityHandler._identityBox.click();
-  ok(hidden(TrackingProtection.container), "The container is hidden");
-  gIdentityHandler._identityPopup.hidden = true;
-});
-
-add_task(async function testPrivateBrowsing() {
-  let privateWin = await promiseOpenAndLoadWindow({private: true}, true);
-  tabbrowser = privateWin.gBrowser;
-  let {gIdentityHandler} = tabbrowser.ownerGlobal;
-  let tab = tabbrowser.selectedTab = tabbrowser.addTab();
-
-  TrackingProtection = tabbrowser.ownerGlobal.TrackingProtection;
-  ok(TrackingProtection, "TP is attached to the private window");
-  is(TrackingProtection.enabled, Services.prefs.getBoolPref(PB_PREF),
-    "TP.enabled is based on the pb pref value");
-
-  Services.prefs.setBoolPref(PB_PREF, true);
-  ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
-
-  Services.prefs.setBoolPref(PB_PREF, false);
-  ok(!TrackingProtection.enabled, "TP is disabled after setting the pref");
-
-  info("Load a test page containing tracking elements");
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
-  gIdentityHandler._identityBox.click();
-  ok(hidden(TrackingProtection.container), "The container is hidden");
-  gIdentityHandler._identityPopup.hidden = true;
-
-  info("Load a test page not containing tracking elements");
-  gIdentityHandler._identityBox.click();
-  await promiseTabLoadEvent(tab, BENIGN_PAGE);
-  ok(hidden(TrackingProtection.container), "The container is hidden");
-  gIdentityHandler._identityPopup.hidden = true;
-
-  privateWin.close();
-});
--- a/browser/components/controlcenter/content/panel.inc.xul
+++ b/browser/components/controlcenter/content/panel.inc.xul
@@ -52,38 +52,46 @@
                 oncommand="gIdentityHandler.showSecuritySubView();"/>
       </hbox>
 
       <!-- Tracking Protection Section -->
       <hbox id="tracking-protection-container"
             class="identity-popup-section"
             when-connection="not-secure secure secure-ev secure-cert-user-overridden file">
         <vbox id="tracking-protection-content" flex="1">
-          <label class="identity-popup-headline"
+          <label id="tracking-protection-label-on"
+                 class="identity-popup-headline"
                  crop="end"
-                 value="&trackingProtection.title;" />
+                 value="&trackingProtection.on;" />
+          <label id="tracking-protection-label-off"
+                 class="identity-popup-headline"
+                 crop="end"
+                 value="&trackingProtection.off;" />
 
           <description id="tracking-blocked"
                        crop="end">&trackingProtection.detectedBlocked3;</description>
           <description id="tracking-loaded"
-                       crop="end">&trackingProtection.detectedNotBlocked3;</description>
+                       crop="end">&trackingProtection.detectedNotBlocked4;</description>
           <description id="tracking-not-detected"
-                       crop="end">&trackingProtection.notDetected3;</description>
+                       crop="end">&trackingProtection.notDetected4;</description>
 
           <button id="tracking-action-unblock"
-                  label="&trackingProtection.unblock.label;"
-                  accesskey="&trackingProtection.unblock.accesskey;"
+                  class="tracking-protection-button"
+                  label="&trackingProtection.unblock2.label;"
+                  accesskey="&trackingProtection.unblock2.accesskey;"
                   oncommand="TrackingProtection.disableForCurrentPage();" />
           <button id="tracking-action-unblock-private"
-                  label="&trackingProtection.unblockPrivate.label;"
-                  accesskey="&trackingProtection.unblockPrivate.accesskey;"
+                  class="tracking-protection-button"
+                  label="&trackingProtection.unblockPrivate2.label;"
+                  accesskey="&trackingProtection.unblockPrivate2.accesskey;"
                   oncommand="TrackingProtection.disableForCurrentPage();" />
           <button id="tracking-action-block"
-                  label="&trackingProtection.block2.label;"
-                  accesskey="&trackingProtection.block2.accesskey;"
+                  class="tracking-protection-button"
+                  label="&trackingProtection.block3.label;"
+                  accesskey="&trackingProtection.block3.accesskey;"
                   oncommand="TrackingProtection.enableForCurrentPage();" />
         </vbox>
       </hbox>
 
       <!-- Permissions Section -->
       <hbox class="identity-popup-section"
             when-connection="not-secure secure secure-ev secure-cert-user-overridden file extension">
         <vbox id="identity-popup-permissions-content" flex="1">
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -208,17 +208,17 @@
             <observes element="sync-status" attribute="onmouseover"/>
           </toolbarbutton>
         </toolbaritem>
         <toolbarseparator class="sync-ui-item"/>
         <toolbaritem>
           <toolbarbutton id="appMenu-tp-label"
                          tooltiptext="&trackingProtection.tooltip;"
                          class="subviewbutton subviewbutton-iconic"
-                         oncommand="TrackingProtection.openPreferences();"
+                         oncommand="TrackingProtection.openPreferences('appMenu-trackingprotection');"
                          label="&trackingProtection.title;"/>
           <toolbarseparator orient="vertical"/>
           <toolbarbutton id="appMenu-tp-toggle"
                          closemenu="none"
                          class="subviewkeynav"
                          observes="trackingProtectionBroadcaster"
                          oncommand="TrackingProtection.onGlobalToggleCommand();" />
         </toolbaritem>
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -892,33 +892,35 @@ you can use these alternative items. Oth
 
 <!ENTITY getUserMedia.selectCamera.label "Camera to share:">
 <!ENTITY getUserMedia.selectCamera.accesskey "C">
 <!ENTITY getUserMedia.selectMicrophone.label "Microphone to share:">
 <!ENTITY getUserMedia.selectMicrophone.accesskey "M">
 <!ENTITY getUserMedia.audioCapture.label "Audio from the tab will be shared.">
 <!ENTITY getUserMedia.allWindowsShared.message "All visible windows on your screen will be shared.">
 
+<!ENTITY trackingProtection.on "Tracking Protection: ON">
+<!ENTITY trackingProtection.off "Tracking Protection: OFF">
 <!ENTITY trackingProtection.title "Tracking Protection">
 <!ENTITY trackingProtection.tooltip "Open Tracking Protection Preferences">
 <!ENTITY trackingProtection.detectedBlocked3 "&brandShortName; is blocking parts of the page that may track your browsing.">
-<!ENTITY trackingProtection.detectedNotBlocked3 "This site includes elements that may track your browsing. You have disabled protection.">
-<!ENTITY trackingProtection.notDetected3 "No tracking elements detected on this page.">
+<!ENTITY trackingProtection.detectedNotBlocked4 "Trackers have been detected on this webpage.">
+<!ENTITY trackingProtection.notDetected4 "No trackers detected on this page.">
 <!-- LOCALIZATION NOTE (trackingProtection.unblock.label, trackingProtection.unblock.accesskey):
      The associated button with this label and accesskey is only shown when opening the control
      center while looking at a site with trackers in NON-private browsing mode. -->
-<!ENTITY trackingProtection.unblock.label "Disable protection for this site">
-<!ENTITY trackingProtection.unblock.accesskey "D">
+<!ENTITY trackingProtection.unblock2.label "Trust this site">
+<!ENTITY trackingProtection.unblock2.accesskey "T">
 <!-- LOCALIZATION NOTE (trackingProtection.unblockPrivate.label, trackingProtection.unblockPrivate.accesskey):
      The associated button with this label and accesskey is only shown when opening the control
      center while looking at a site with trackers in PRIVATE browsing mode. -->
-<!ENTITY trackingProtection.unblockPrivate.label "Disable protection for this session">
-<!ENTITY trackingProtection.unblockPrivate.accesskey "D">
-<!ENTITY trackingProtection.block2.label "Enable protection">
-<!ENTITY trackingProtection.block2.accesskey "E">
+<!ENTITY trackingProtection.unblockPrivate2.label "Trust this site for this session">
+<!ENTITY trackingProtection.unblockPrivate2.accesskey "T">
+<!ENTITY trackingProtection.block3.label "Turn Tracking Protection ON">
+<!ENTITY trackingProtection.block3.accesskey "T">
 
 <!ENTITY pluginNotification.showAll.label "Show All">
 <!ENTITY pluginNotification.showAll.accesskey "S">
 
 <!-- LOCALIZATION NOTE (pluginActivateNow.label, pluginActivateAlways.label, pluginBlockNow.label): These should be the same as the matching strings in browser.properties -->
 <!ENTITY pluginActivateNow.label "Allow Now">
 <!ENTITY pluginActivateAlways.label "Allow and Remember">
 <!ENTITY pluginBlockNow.label "Block Plugin">
--- a/browser/themes/osx/controlcenter/panel.css
+++ b/browser/themes/osx/controlcenter/panel.css
@@ -5,29 +5,23 @@
 %include ../shared.inc
 %include ../../shared/controlcenter/panel.inc.css
 
 .identity-popup-expander:-moz-focusring,
 .identity-popup-permission-remove-button:-moz-focusring {
   box-shadow: var(--focus-ring-box-shadow);
 }
 
-#tracking-action-block,
-#tracking-action-unblock,
-#tracking-action-unblock-private,
+.tracking-protection-button,
 #identity-popup-securityView-body > button {
   @hudButton@
   min-height: 30px;
 }
 
-#tracking-action-block:hover:active,
-#tracking-action-unblock:hover:active,
-#tracking-action-unblock-private:hover:active,
+.tracking-protection-button:hover:active,
 #identity-popup-securityView-body > button:hover:active {
   @hudButtonPressed@
 }
 
-#tracking-action-block:-moz-focusring,
-#tracking-action-unblock:-moz-focusring,
-#tracking-action-unblock-private:-moz-focusring,
+.tracking-protection-button:-moz-focusring,
 #identity-popup-securityView-body > button:-moz-focusring {
   box-shadow: var(--focus-ring-box-shadow);
 }
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -284,38 +284,57 @@ description#identity-popup-content-verif
 }
 
 /* TRACKING PROTECTION */
 
 #tracking-protection-content {
   background-image: url("chrome://browser/skin/controlcenter/tracking-protection.svg#enabled");
 }
 
-#tracking-protection-content[state="loaded-tracking-content"]  {
+#tracking-protection-content[enabled="false"],
+#tracking-protection-content[state="loaded-tracking-content"] {
   background-image: url("chrome://browser/skin/controlcenter/tracking-protection.svg#disabled");
 }
 
-#tracking-action-block,
-#tracking-action-unblock,
-#tracking-action-unblock-private {
-  margin: 1em 0 0;
+/* Show the "on" label by default, except when TP is disabled or there's a local exception. */
+#tracking-protection-label-off,
+#tracking-protection-content[enabled="false"] > #tracking-protection-label-on,
+#tracking-protection-content[state="loaded-tracking-content"] > #tracking-protection-label-on {
+  display: none;
+}
+
+#tracking-protection-label-on,
+#tracking-protection-content[enabled="false"] > #tracking-protection-label-off,
+#tracking-protection-content[state="loaded-tracking-content"] > #tracking-protection-label-off {
+  display: -moz-box;
+}
+
+#tracking-protection-content > description {
+  display: none;
 }
 
-#tracking-protection-content[state] > #tracking-not-detected,
-#tracking-protection-content:not([state="blocked-tracking-content"]) > #tracking-blocked,
-#main-window[privatebrowsingmode] #tracking-action-unblock,
-#main-window:not([privatebrowsingmode]) #tracking-action-unblock-private,
-#tracking-protection-content:not([state="blocked-tracking-content"]) #tracking-action-unblock,
-#tracking-protection-content:not([state="blocked-tracking-content"]) #tracking-action-unblock-private,
-#tracking-protection-content:not([state="loaded-tracking-content"]) > #tracking-loaded,
-#tracking-protection-content:not([state="loaded-tracking-content"]) #tracking-action-block,
-#tracking-protection-content:not([state]) > #tracking-actions {
+.tracking-protection-button {
+  margin: 1em 0 0;
   display: none;
 }
 
+/* Show the right tracking descriptions and buttons for the corresponding state. */
+
+/* Default state / Tracking not detected */
+#tracking-protection-content:not([state]) > #tracking-not-detected,
+/* Blocking tracking, offer buttons to unblock (depending on PBM). */
+#tracking-protection-content[state="blocked-tracking-content"] > #tracking-blocked,
+#main-window:not([privatebrowsingmode]) #tracking-protection-content[state="blocked-tracking-content"] > #tracking-action-unblock,
+#main-window[privatebrowsingmode] #tracking-protection-content[state="blocked-tracking-content"] > #tracking-action-unblock-private,
+/* Disabled or has an exception, offer to block the site. */
+#tracking-protection-content[state="loaded-tracking-content"]:-moz-any([enabled="false"],[hasException]) > #tracking-loaded,
+#tracking-protection-content[state="loaded-tracking-content"]:-moz-any([enabled="false"],[hasException]) > #tracking-action-block {
+  display: -moz-box;
+}
+
 /* PERMISSIONS */
 
 #identity-popup-permissions-content {
   background-image: url(chrome://browser/skin/controlcenter/permissions.svg);
   padding-bottom: 1.5em;
 }
 
 @supports -moz-bool-pref("layout.css.emulate-moz-box-with-flex") {
--- a/toolkit/modules/PrivateBrowsingUtils.jsm
+++ b/toolkit/modules/PrivateBrowsingUtils.jsm
@@ -1,15 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var EXPORTED_SYMBOLS = ["PrivateBrowsingUtils"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "gPBMTPWhitelist",
+                                   "@mozilla.org/pbm-tp-whitelist;1",
+                                   "nsIPrivateBrowsingTrackingProtectionWhitelist");
 
 const kAutoStartPref = "browser.privatebrowsing.autostart";
 
 // This will be set to true when the PB mode is autostarted from the command
 // line for the current session.
 var gTemporaryAutoStartMode = false;
 
 var PrivateBrowsingUtils = {
@@ -49,25 +54,25 @@ var PrivateBrowsingUtils = {
 
   privacyContextFromWindow: function pbu_privacyContextFromWindow(aWindow) {
     return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                   .getInterface(Ci.nsIWebNavigation)
                   .QueryInterface(Ci.nsILoadContext);
   },
 
   addToTrackingAllowlist(aURI) {
-    let pbmtpWhitelist = Cc["@mozilla.org/pbm-tp-whitelist;1"]
-                           .getService(Ci.nsIPrivateBrowsingTrackingProtectionWhitelist);
-    pbmtpWhitelist.addToAllowList(aURI);
+    gPBMTPWhitelist.addToAllowList(aURI);
+  },
+
+  existsInTrackingAllowlist(aURI) {
+    return gPBMTPWhitelist.existsInAllowList(aURI);
   },
 
   removeFromTrackingAllowlist(aURI) {
-    let pbmtpWhitelist = Cc["@mozilla.org/pbm-tp-whitelist;1"]
-                           .getService(Ci.nsIPrivateBrowsingTrackingProtectionWhitelist);
-    pbmtpWhitelist.removeFromAllowList(aURI);
+    gPBMTPWhitelist.removeFromAllowList(aURI);
   },
 
   get permanentPrivateBrowsing() {
     try {
       return gTemporaryAutoStartMode ||
              Services.prefs.getBoolPref(kAutoStartPref);
     } catch (e) {
       // The pref does not exist