--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1471,16 +1471,23 @@ pref("toolkit.telemetry.hybridContent.en
pref("browser.ping-centre.telemetry", true);
pref("browser.ping-centre.log", false);
pref("browser.ping-centre.staging.endpoint", "https://onyx_tiles.stage.mozaws.net/v3/links/ping-centre");
pref("browser.ping-centre.production.endpoint", "https://tiles.services.mozilla.com/v3/links/ping-centre");
// Enable GMP support in the addon manager.
pref("media.gmp-provider.enabled", true);
+pref("browser.contentblocking.enabled", true);
+#ifdef NIGHTLY_BUILD
+pref("browser.contentblocking.ui.enabled", true);
+#else
+pref("browser.contentblocking.ui.enabled", false);
+#endif
+
pref("privacy.trackingprotection.introCount", 0);
pref("privacy.trackingprotection.introURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tracking-protection/start/");
#ifdef NIGHTLY_BUILD
pref("privacy.trackingprotection.appMenuToggle.enabled", true);
#else
pref("privacy.trackingprotection.appMenuToggle.enabled", false);
#endif
--- a/browser/components/preferences/in-content/extensionControlled.js
+++ b/browser/components/preferences/in-content/extensionControlled.js
@@ -12,16 +12,19 @@ ChromeUtils.defineModuleGetter(this, "Ad
"resource://gre/modules/AddonManager.jsm");
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
ChromeUtils.defineModuleGetter(this, "DeferredTask",
"resource://gre/modules/DeferredTask.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
+XPCOMUtils.defineLazyPreferenceGetter(this, "contentBlockingUiEnabled",
+ "browser.contentblocking.ui.enabled");
+
const PREF_SETTING_TYPE = "prefs";
const PROXY_KEY = "proxy.settings";
const API_PROXY_PREFS = [
"network.proxy.type",
"network.proxy.http",
"network.proxy.http_port",
"network.proxy.share_proxy_settings",
"network.proxy.ftp",
@@ -40,18 +43,22 @@ const API_PROXY_PREFS = [
let extensionControlledContentIds = {
"privacy.containers": "browserContainersExtensionContent",
"homepage_override": "browserHomePageExtensionContent",
"newTabURL": "browserNewTabExtensionContent",
"defaultSearch": "browserDefaultSearchExtensionContent",
"proxy.settings": "proxyExtensionContent",
get "websites.trackingProtectionMode"() {
return {
- button: "trackingProtectionExtensionContentButton",
- section: "trackingProtectionExtensionContentLabel",
+ button: contentBlockingUiEnabled ?
+ "contentBlockingTrackingProtectionExtensionContentButton" :
+ "trackingProtectionExtensionContentButton",
+ section: contentBlockingUiEnabled ?
+ "contentBlockingTrackingProtectionExtensionContentLabel" :
+ "trackingProtectionExtensionContentLabel",
};
}
};
const extensionControlledL10nKeys = {
"homepage_override": "homepage-override",
"newTabURL": "new-tab-url",
"defaultSearch": "default-search",
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -15,16 +15,19 @@ ChromeUtils.defineModuleGetter(this, "Pl
"resource://gre/modules/PluralForm.jsm");
ChromeUtils.defineModuleGetter(this, "LoginHelper",
"resource://gre/modules/LoginHelper.jsm");
ChromeUtils.defineModuleGetter(this, "SiteDataManager",
"resource:///modules/SiteDataManager.jsm");
ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyPreferenceGetter(this, "contentBlockingUiEnabled",
+ "browser.contentblocking.ui.enabled");
+
const PREF_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
const TRACKING_PROTECTION_KEY = "websites.trackingProtectionMode";
const TRACKING_PROTECTION_PREFS = ["privacy.trackingprotection.enabled",
"privacy.trackingprotection.pbmode.enabled"];
const PREF_OPT_OUT_STUDIES_ENABLED = "app.shield.optoutstudies.enabled";
const PREF_NORMANDY_ENABLED = "app.normandy.enabled";
@@ -38,17 +41,20 @@ XPCOMUtils.defineLazyGetter(this, "Alert
alertsService.manualDoNotDisturb;
return alertsService;
} catch (ex) {
return undefined;
}
});
Preferences.addAll([
- // Tracking
+ // Content Blocking
+ { id: "browser.contentblocking.enabled", type: "bool" },
+
+ // Tracking Protection
{ id: "privacy.trackingprotection.enabled", type: "bool" },
{ id: "privacy.trackingprotection.pbmode.enabled", type: "bool" },
// Button prefs
{ id: "pref.privacy.disable_button.cookie_exceptions", type: "bool" },
{ id: "pref.privacy.disable_button.view_cookies", type: "bool" },
{ id: "pref.privacy.disable_button.change_blocklist", type: "bool" },
{ id: "pref.privacy.disable_button.tracking_protection_exceptions", type: "bool" },
@@ -131,50 +137,61 @@ if (AppConstants.MOZ_DATA_REPORTING) {
// Data Choices tab
if (AppConstants.NIGHTLY_BUILD) {
Preferences.add({ id: "browser.chrome.errorReporter.enabled", type: "bool" });
}
if (AppConstants.MOZ_CRASHREPORTER) {
Preferences.add({ id: "browser.crashReports.unsubmittedCheck.autoSubmit2", type: "bool" });
}
+function setEventListener(aId, aEventType, aCallback) {
+ document.getElementById(aId)
+ .addEventListener(aEventType, aCallback.bind(gPrivacyPane));
+}
+
var gPrivacyPane = {
_pane: null,
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
_shouldPromptForRestart: true,
/**
* Initialize the tracking protection prefs and linkify its Learn More link.
*/
_initTrackingProtection() {
+ setEventListener("trackingProtectionRadioGroup", "command",
+ this.trackingProtectionWritePrefs);
+ setEventListener("changeBlockList", "command", this.showBlockLists);
+
let link = document.getElementById("trackingProtectionLearnMore");
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "tracking-protection";
link.setAttribute("href", url);
-
- this.trackingProtectionReadPrefs();
},
/**
* Update the tracking protection UI to deal with extension control.
*/
_updateTrackingProtectionUI() {
let isLocked = TRACKING_PROTECTION_PREFS.some(
pref => Services.prefs.prefIsLocked(pref));
function setInputsDisabledState(isControlled) {
let disabled = isLocked || isControlled;
- document.querySelectorAll("#trackingProtectionRadioGroup > radio")
- .forEach((element) => {
- element.disabled = disabled;
- });
- document.querySelector("#trackingProtectionDesc > label")
- .disabled = disabled;
+ if (contentBlockingUiEnabled) {
+ document.getElementById("trackingProtectionMenu").disabled = disabled;
+ } else {
+ document.querySelectorAll("#trackingProtectionRadioGroup > radio")
+ .forEach((element) => {
+ element.disabled = disabled;
+ });
+ document.querySelector("#trackingProtectionDesc > label")
+ .disabled = disabled;
+ }
}
if (isLocked) {
// An extension can't control this setting if either pref is locked.
hideControllingExtension(TRACKING_PROTECTION_KEY);
setInputsDisabledState(false);
} else {
handleControllingExtension(
@@ -184,16 +201,22 @@ var gPrivacyPane = {
}
},
/**
* Set up handlers for showing and hiding controlling extension info
* for tracking protection.
*/
_initTrackingProtectionExtensionControl() {
+ let disableButton = contentBlockingUiEnabled ?
+ "contentBlockingDisableTrackingProtectionExtension" : "disableTrackingProtectionExtension";
+ setEventListener(disableButton, "command",
+ makeDisableControllingExtension(
+ PREF_SETTING_TYPE, TRACKING_PROTECTION_KEY));
+
let trackingProtectionObserver = {
observe(subject, topic, data) {
gPrivacyPane._updateTrackingProtectionUI();
},
};
for (let pref of TRACKING_PROTECTION_PREFS) {
Services.prefs.addObserver(pref, trackingProtectionObserver);
@@ -213,39 +236,49 @@ var gPrivacyPane = {
.getService(Ci.mozIPlacesAutoComplete);
},
/**
* Sets up the UI for the number of days of history to keep, and updates the
* label of the "Clear Now..." button.
*/
init() {
- function setEventListener(aId, aEventType, aCallback) {
- document.getElementById(aId)
- .addEventListener(aEventType, aCallback.bind(gPrivacyPane));
- }
-
this._updateSanitizeSettingsButton();
this.initializeHistoryMode();
this.updateAutoplayMediaControlsVisibility();
this.updateHistoryModePane();
this.updatePrivacyMicroControls();
this.initAutoStartPrivateBrowsingReverter();
- this._initTrackingProtection();
+ this._initAutocomplete();
+
+ /* Initialize Content Blocking / Tracking Protection */
+
+ if (contentBlockingUiEnabled) {
+ this.initContentBlocking();
+ } else {
+ this._initTrackingProtection();
+ }
+
+ this.trackingProtectionReadPrefs();
this._initTrackingProtectionExtensionControl();
- this._initAutocomplete();
+
+ this.updateContentBlockingVisibility();
+
+ Preferences.get("privacy.trackingprotection.enabled").on("change",
+ gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane));
+ Preferences.get("privacy.trackingprotection.pbmode.enabled").on("change",
+ gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane));
+
+ setEventListener("trackingProtectionExceptions", "command",
+ gPrivacyPane.showTrackingProtectionExceptions);
Preferences.get("privacy.sanitize.sanitizeOnShutdown").on("change",
gPrivacyPane._updateSanitizeSettingsButton.bind(gPrivacyPane));
Preferences.get("browser.privatebrowsing.autostart").on("change",
gPrivacyPane.updatePrivacyMicroControls.bind(gPrivacyPane));
- Preferences.get("privacy.trackingprotection.enabled").on("change",
- gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane));
- Preferences.get("privacy.trackingprotection.pbmode.enabled").on("change",
- gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane));
Preferences.get("media.autoplay.enabled.ask-permission").on("change",
gPrivacyPane.updateAutoplayMediaControlsVisibility.bind(gPrivacyPane));
Preferences.get("media.autoplay.enabled.user-gestures-needed").on("change",
gPrivacyPane.updateAutoplayMediaControlsVisibility.bind(gPrivacyPane));
setEventListener("historyMode", "command", function() {
gPrivacyPane.updateHistoryModePane();
gPrivacyPane.updateHistoryModePrefs();
gPrivacyPane.updatePrivacyMicroControls();
@@ -264,25 +297,16 @@ var gPrivacyPane = {
return false;
});
setEventListener("privateBrowsingAutoStart", "command",
gPrivacyPane.updateAutostart);
setEventListener("cookieExceptions", "command",
gPrivacyPane.showCookieExceptions);
setEventListener("clearDataSettings", "command",
gPrivacyPane.showClearPrivateDataSettings);
- setEventListener("disableTrackingProtectionExtension", "command",
- makeDisableControllingExtension(
- PREF_SETTING_TYPE, TRACKING_PROTECTION_KEY));
- setEventListener("trackingProtectionRadioGroup", "command",
- gPrivacyPane.trackingProtectionWritePrefs);
- setEventListener("trackingProtectionExceptions", "command",
- gPrivacyPane.showTrackingProtectionExceptions);
- setEventListener("changeBlockList", "command",
- gPrivacyPane.showBlockLists);
setEventListener("passwordExceptions", "command",
gPrivacyPane.showPasswordExceptions);
setEventListener("useMasterPassword", "command",
gPrivacyPane.updateMasterPasswordButton);
setEventListener("changeMasterPassword", "command",
gPrivacyPane.changeMasterPassword);
setEventListener("showPasswords", "command",
gPrivacyPane.showPasswords);
@@ -390,47 +414,114 @@ var gPrivacyPane = {
document.getElementById("privateBrowsingAutoStart").hidden = true;
document.querySelector("menuitem[value='dontremember']").hidden = true;
}
// Notify observers that the UI is now ready
Services.obs.notifyObservers(window, "privacy-pane-loaded");
},
+ // CONTENT BLOCKING
+
+ /**
+ * Initializes the content blocking section.
+ */
+ initContentBlocking() {
+ let contentBlockingCheckbox = document.getElementById("contentBlockingCheckbox");
+ setEventListener("contentBlockingToggle", "command",
+ () => contentBlockingCheckbox.click());
+ setEventListener("changeBlockListLink", "click", this.showBlockLists);
+ setEventListener("trackingProtectionMenu", "command",
+ this.trackingProtectionWritePrefs);
+
+ let link = document.getElementById("contentBlockingLearnMore");
+ let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "tracking-protection";
+ link.setAttribute("href", url);
+ },
+
+ /**
+ * Changes the visibility of elements in the TP/CB section depending on the
+ * content blocking UI pref.
+ */
+ updateContentBlockingVisibility() {
+ let visibleState = {
+ "contentBlockingHeader": true,
+ "contentBlockingDescription": true,
+ "contentBlockingLearnMore": true,
+ "contentBlockingRestoreDefaults": true,
+ "contentBlockingCheckboxContainer": true,
+ "contentBlockingCategories": true,
+
+ "trackingProtectionHeader": false,
+ "trackingProtectionDescription": false,
+ "trackingProtectionBox": false,
+ };
+ for (let id in visibleState) {
+ document.getElementById(id).hidden = contentBlockingUiEnabled != visibleState[id];
+ }
+ },
+
+ /**
+ * Updates the preferences UI to reflect the browser.contentblocking.enabled pref.
+ * This affects the button to toggle the pref and the disabled state of the dependent controls.
+ */
+ updateContentBlockingToggle() {
+ let enabled = Services.prefs.getBoolPref("browser.contentblocking.enabled");
+ let onOrOff = enabled ? "on" : "off";
+ let contentBlockingToggle = document.getElementById("contentBlockingToggle");
+ let contentBlockingToggleLabel = document.getElementById("contentBlockingToggleLabel");
+
+ document.l10n.setAttributes(contentBlockingToggle,
+ "content-blocking-toggle-" + onOrOff);
+ contentBlockingToggle.setAttribute("aria-pressed", enabled);
+ document.l10n.setAttributes(contentBlockingToggleLabel,
+ "content-blocking-toggle-label-" + onOrOff);
+ },
+
// TRACKING PROTECTION MODE
/**
* Selects the right item of the Tracking Protection radiogroup.
*/
trackingProtectionReadPrefs() {
let enabledPref = Preferences.get("privacy.trackingprotection.enabled");
let pbmPref = Preferences.get("privacy.trackingprotection.pbmode.enabled");
- let radiogroup = document.getElementById("trackingProtectionRadioGroup");
+ let tpControl;
+ if (contentBlockingUiEnabled) {
+ tpControl = document.getElementById("trackingProtectionMenu");
+ } else {
+ tpControl = document.getElementById("trackingProtectionRadioGroup");
+ }
this._updateTrackingProtectionUI();
// Global enable takes precedence over enabled in Private Browsing.
if (enabledPref.value) {
- radiogroup.value = "always";
+ tpControl.value = "always";
} else if (pbmPref.value) {
- radiogroup.value = "private";
+ tpControl.value = "private";
} else {
- radiogroup.value = "never";
+ tpControl.value = "never";
}
},
/**
* Sets the pref values based on the selected item of the radiogroup.
*/
trackingProtectionWritePrefs() {
let enabledPref = Preferences.get("privacy.trackingprotection.enabled");
let pbmPref = Preferences.get("privacy.trackingprotection.pbmode.enabled");
- let radiogroup = document.getElementById("trackingProtectionRadioGroup");
+ let tpControl;
+ if (contentBlockingUiEnabled) {
+ tpControl = document.getElementById("trackingProtectionMenu");
+ } else {
+ tpControl = document.getElementById("trackingProtectionRadioGroup");
+ }
- switch (radiogroup.value) {
+ switch (tpControl.value) {
case "always":
enabledPref.value = true;
pbmPref.value = true;
break;
case "private":
enabledPref.value = false;
pbmPref.value = true;
break;
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -275,30 +275,105 @@
<checkbox id="bookmarkSuggestion" data-l10n-id="addressbar-locbar-bookmarks-option"
preference="browser.urlbar.suggest.bookmark"/>
<checkbox id="openpageSuggestion" data-l10n-id="addressbar-locbar-openpage-option"
preference="browser.urlbar.suggest.openpage"/>
<label class="text-link" id="openSearchEnginePreferences"
data-l10n-id="addressbar-suggestions-settings"/>
</groupbox>
-<!-- Tracking -->
+<!-- Tracking / Content Blocking -->
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true">
- <caption><label data-l10n-id="tracking-header"/></caption>
+ <caption>
+ <label id="trackingProtectionHeader" hidden="true" data-l10n-id="tracking-header"/>
+ <label id="contentBlockingHeader" data-l10n-id="content-blocking-header"/>
+ </caption>
<vbox data-subcategory="trackingprotection">
<hbox align="start">
<vbox flex="1">
- <description data-l10n-id="tracking-desc">
+ <description id="trackingProtectionDescription" class="description-with-side-element" hidden="true" data-l10n-id="tracking-desc">
<html:a id="trackingProtectionLearnMore" data-l10n-name="learn-more" target="_blank" class="learnMore text-link"/>
</description>
+ <description id="contentBlockingDescription" class="description-with-side-element" data-l10n-id="content-blocking-desc"></description>
+ <label id="contentBlockingLearnMore" data-l10n-id="content-blocking-learn-more" class="learnMore text-link"/>
</vbox>
- <spacer flex="1"/>
+ <vbox>
+ <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
+ <hbox>
+ <button id="trackingProtectionExceptions"
+ class="accessory-button"
+ flex="1"
+ data-l10n-id="tracking-exceptions"
+ preference="pref.privacy.disable_button.tracking_protection_exceptions"
+ search-l10n-ids="
+ permissions-remove.label,
+ permissions-remove-all.label,
+ permissions-button-cancel.label,
+ permissions-button-ok.label,
+ permissions-exceptions-tracking-protection-window.title,
+ permissions-exceptions-tracking-protection-desc,
+ "/>
+ </hbox>
+ </vbox>
+ </hbox>
+ <hbox id="contentBlockingCheckboxContainer">
+ <checkbox id="contentBlockingCheckbox"
+ onsyncfrompreference="return gPrivacyPane.updateContentBlockingToggle()"
+ preference="browser.contentblocking.enabled"/>
+ <button id="contentBlockingToggle"
+ data-l10n-id="content-blocking-toggle-on"/>
+ <label id="contentBlockingToggleLabel"
+ data-l10n-id="content-blocking-toggle-label-on"
+ control="contentBlockingToggle"/>
</hbox>
- <hbox>
- <vbox id="trackingProtectionBox" flex="1">
+ <vbox id="contentBlockingCategories">
+ <label id="content-blocking-categories-label" data-l10n-id="content-blocking-category-label"/>
+ <vbox>
+ <hbox id="contentBlockingTrackingProtectionExtensionContentLabel" align="center" hidden="true">
+ <description control="contentBlockingDisableTrackingProtectionExtension" flex="1"/>
+ </hbox>
+ <hbox id="contentBlockingTrackingProtectionExtensionContentButton" hidden="true">
+ <button id="contentBlockingDisableTrackingProtectionExtension"
+ class="extension-controlled-button accessory-button"
+ data-l10n-id="disable-extension"/>
+ </hbox>
+ <hbox class="content-blocking-category">
+ <vbox class="content-blocking-category-icon">
+ <image class="tracking-protection-icon content-blocking-icon" />
+ </vbox>
+ <vbox class="content-blocking-category-labels" flex="1">
+ <label data-l10n-id="content-blocking-tracking-protection-label"
+ class="content-blocking-category-name"
+ control="trackingProtectionMenu"/>
+ <description data-l10n-id="content-blocking-tracking-protection-description" class="content-blocking-category-description"/>
+ <label id="changeBlockListLink" data-l10n-id="content-blocking-tracking-protection-change-blocklist" class="text-link"/>
+ </vbox>
+ <vbox>
+ <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
+ <hbox>
+ <menulist class="content-blocking-category-menu" id="trackingProtectionMenu">
+ <menupopup>
+ <menuitem data-l10n-id="content-blocking-tracking-protection-option-enabled"
+ value="always"
+ search-l10n-ids=""/>
+ <menuitem data-l10n-id="content-blocking-tracking-protection-option-pbm"
+ value="private"
+ search-l10n-ids=""/>
+ <menuitem data-l10n-id="content-blocking-tracking-protection-option-disabled"
+ value="never"
+ search-l10n-ids=""/>
+ </menupopup>
+ </menulist>
+ </hbox>
+ </vbox>
+ </hbox>
+ </vbox>
+ </vbox>
+ <hbox id="trackingProtectionBox" hidden="true">
+ <vbox flex="1">
<vbox>
<hbox id="trackingProtectionExtensionContentLabel" align="center" hidden="true">
<description control="disableTrackingProtectionExtension" flex="1"/>
</hbox>
<vbox>
<description id="trackingProtectionDesc"
control="trackingProtectionRadioGroup">
<label data-l10n-id="tracking-mode-label"/>
@@ -318,32 +393,16 @@
<hbox id="trackingProtectionExtensionContentButton" hidden="true">
<button id="disableTrackingProtectionExtension"
class="extension-controlled-button accessory-button"
flex="1"
data-l10n-id="disable-extension"/>
</hbox>
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
<hbox>
- <button id="trackingProtectionExceptions"
- class="accessory-button"
- flex="1"
- data-l10n-id="tracking-exceptions"
- preference="pref.privacy.disable_button.tracking_protection_exceptions"
- search-l10n-ids="
- permissions-remove.label,
- permissions-remove-all.label,
- permissions-button-cancel.label,
- permissions-button-ok.label,
- permissions-exceptions-tracking-protection-window.title,
- permissions-exceptions-tracking-protection-desc,
- "/>
- </hbox>
- <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
- <hbox>
<button id="changeBlockList"
class="accessory-button"
flex="1"
data-l10n-id="tracking-change-block-list"
preference="pref.privacy.disable_button.change_blocklist"
search-l10n-ids="blocklist-window.title, blocklist-desc, blocklist-button-cancel.label, blocklist-button-ok.label"/>
</hbox>
</vbox>
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -511,114 +511,146 @@ add_task(async function testExtensionCon
// Don't finalize the current store since it will write out the bad data.
await ExtensionSettingsStore._reloadFile(false);
is(ExtensionSettingsStore.getSetting("prefs", "homepage_override"), null,
"The ExtensionSettingsStore is left empty.");
});
add_task(async function testExtensionControlledTrackingProtection() {
+ const CB_UI_PREF = "browser.contentblocking.ui.enabled";
const TP_PREF = "privacy.trackingprotection.enabled";
const TP_DEFAULT = false;
const EXTENSION_ID = "@set_tp";
- const CONTROLLED_LABEL_ID = "trackingProtectionExtensionContentLabel";
- const CONTROLLED_BUTTON_ID = "trackingProtectionExtensionContentButton";
+ const CONTROLLED_LABEL_ID = {
+ old: "trackingProtectionExtensionContentLabel",
+ new: "contentBlockingTrackingProtectionExtensionContentLabel",
+ };
+ const CONTROLLED_BUTTON_ID = {
+ old: "trackingProtectionExtensionContentButton",
+ new: "contentBlockingTrackingProtectionExtensionContentButton"
+ };
+ const DISABLE_BUTTON_ID = {
+ old: "disableTrackingProtectionExtension",
+ new: "contentBlockingDisableTrackingProtectionExtension"
+ };
let tpEnabledPref = () => Services.prefs.getBoolPref(TP_PREF);
await SpecialPowers.pushPrefEnv(
- {"set": [[TP_PREF, TP_DEFAULT]]});
+ {"set": [[TP_PREF, TP_DEFAULT], [CB_UI_PREF, true]]});
function background() {
browser.privacy.websites.trackingProtectionMode.set({value: "always"});
}
function verifyState(isControlled) {
is(tpEnabledPref(), isControlled, "TP pref is set to the expected value.");
- let controlledLabel = doc.getElementById(CONTROLLED_LABEL_ID);
+ let controlledLabel = doc.getElementById(CONTROLLED_LABEL_ID[uiType]);
+ let controlledButton = doc.getElementById(CONTROLLED_BUTTON_ID[uiType]);
is(controlledLabel.hidden, !isControlled, "The extension controlled row's visibility is as expected.");
is(controlledButton.hidden, !isControlled, "The disable extension button's visibility is as expected.");
if (isControlled) {
let controlledDesc = controlledLabel.querySelector("description");
Assert.deepEqual(doc.l10n.getAttributes(controlledDesc), {
id: "extension-controlled-websites-tracking-protection-mode",
args: {
name: "set_tp",
}
}, "The user is notified that an extension is controlling TP.");
}
- for (let element of doc.querySelectorAll("#trackingProtectionRadioGroup > radio")) {
- is(element.disabled, isControlled, "TP controls are enabled.");
+ if (uiType === "old") {
+ for (let element of doc.querySelectorAll("#trackingProtectionRadioGroup > radio")) {
+ is(element.disabled, isControlled, "TP controls are enabled.");
+ }
+ is(doc.querySelector("#trackingProtectionDesc > label").disabled,
+ isControlled,
+ "TP control label is enabled.");
+ } else {
+ is(doc.getElementById("trackingProtectionMenu").disabled,
+ isControlled,
+ "TP control is enabled.");
}
- is(doc.querySelector("#trackingProtectionDesc > label").disabled,
- isControlled,
- "TP control label is enabled.");
}
async function disableViaClick() {
- let labelId = CONTROLLED_LABEL_ID;
+ let labelId = CONTROLLED_LABEL_ID[uiType];
+ let disableId = DISABLE_BUTTON_ID[uiType];
let controlledLabel = doc.getElementById(labelId);
let enableMessageShown = waitForEnableMessage(labelId);
- doc.getElementById("disableTrackingProtectionExtension").click();
+ doc.getElementById(disableId).click();
await enableMessageShown;
// The user is notified how to enable the extension.
let controlledDesc = controlledLabel.querySelector("description");
is(doc.l10n.getAttributes(controlledDesc.querySelector("label")).id,
"extension-controlled-enable",
"The user is notified of how to enable the extension again");
// The user can dismiss the enable instructions.
let hidden = waitForMessageHidden(labelId);
controlledLabel.querySelector("image:last-of-type").click();
await hidden;
}
async function reEnableExtension(addon) {
- let controlledMessageShown = waitForMessageShown(CONTROLLED_LABEL_ID);
+ let controlledMessageShown = waitForMessageShown(CONTROLLED_LABEL_ID[uiType]);
await addon.enable();
await controlledMessageShown;
}
+ let uiType = "new";
+
await openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true});
let doc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#privacy",
"#privacy should be in the URI for about:preferences");
- let controlledButton = doc.getElementById(CONTROLLED_BUTTON_ID);
-
verifyState(false);
// Install an extension that sets Tracking Protection.
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
name: "set_tp",
applications: {gecko: {id: EXTENSION_ID}},
permissions: ["privacy"],
},
background,
});
- let messageShown = waitForMessageShown(CONTROLLED_LABEL_ID);
+ let messageShown = waitForMessageShown(CONTROLLED_LABEL_ID[uiType]);
await extension.startup();
await messageShown;
let addon = await AddonManager.getAddonByID(EXTENSION_ID);
verifyState(true);
await disableViaClick();
verifyState(false);
+ // Switch to the "old" Tracking Protection UI.
+ uiType = "old";
+ Services.prefs.setBoolPref(CB_UI_PREF, false);
+
+ let browserLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, "about:preferences#privacy");
+ gBrowser.selectedBrowser.reload();
+ await browserLoaded;
+ is(gBrowser.currentURI.spec, "about:preferences#privacy",
+ "#privacy should be in the URI for about:preferences");
+ doc = gBrowser.contentDocument;
+
+ verifyState(false);
+
await reEnableExtension(addon);
verifyState(true);
await disableViaClick();
verifyState(false);
--- a/browser/locales/en-US/browser/preferences/preferences.ftl
+++ b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -784,16 +784,47 @@ addressbar-locbar-bookmarks-option =
.label = Bookmarks
.accesskey = k
addressbar-locbar-openpage-option =
.label = Open tabs
.accesskey = O
addressbar-suggestions-settings = Change preferences for search engine suggestions
+## Privacy Section - Content Blocking
+
+content-blocking-header = Content Blocking
+
+content-blocking-desc = Block third-party content, like ads or code, that can slow your browsing and track you around the web. Customize your settings for the best balance of protection and performance.
+
+content-blocking-learn-more = Learn More
+
+content-blocking-toggle-on =
+ .tooltiptext = Turn Off Content Blocking
+content-blocking-toggle-off =
+ .tooltiptext = Turn On Content Blocking
+
+content-blocking-toggle-label-on = ON
+ .accesskey = O
+content-blocking-toggle-label-off = OFF
+ .accesskey = O
+
+content-blocking-category-label = Choose what to block
+
+content-blocking-tracking-protection-label = Trackers
+ .accesskey = T
+content-blocking-tracking-protection-description = Blocks all known trackers (Note: may also prevent some pages from loading).
+content-blocking-tracking-protection-option-enabled =
+ .label = Always block
+content-blocking-tracking-protection-option-pbm =
+ .label = Block only in private windows
+content-blocking-tracking-protection-option-disabled =
+ .label = Never block
+content-blocking-tracking-protection-change-blocklist = Change Block List…
+
## Privacy Section - Tracking
tracking-header = Tracking Protection
tracking-desc = Tracking Protection blocks online trackers that collect your browsing data across multiple websites. <a data-l10n-name="learn-more">Learn more about Tracking Protection and your privacy</a>
tracking-mode-label = Use Tracking Protection to block known trackers
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/controlcenter/trackers.svg
@@ -0,0 +1,9 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
+ <path d="M4.414,0C2.8.2,1.766,2.521,2.045,4.742c.143,1.133.828,1.675,1.028,3.707.019.194.036.37.052.536A18.56,18.56,0,0,0,6.6,8.8,4.988,4.988,0,0,1,6.545,7.79a25.267,25.267,0,0,0,.432-3.949C6.724,1.833,5.853-.177,4.414,0Z"/>
+ <path d="M6.766,9.771A18.373,18.373,0,0,1,3.854,10c-.221,0-.432,0-.636-.01a8.709,8.709,0,0,0,.2,1.351c.165.659.71,1.8,1.944,1.635A1.675,1.675,0,0,0,6.942,10.9C6.9,10.506,6.834,10.134,6.766,9.771Z"/>
+ <path d="M11.588,3c-1.439-.18-2.311,1.83-2.564,3.838a25.267,25.267,0,0,0,.432,3.949,4.938,4.938,0,0,1-.058,1,18.45,18.45,0,0,0,3.478.193c.016-.167.033-.343.052-.537.2-2.032.885-2.574,1.028-3.707C14.235,5.521,13.2,3.2,11.588,3Z"/>
+ <path d="M9.236,12.767c-.069.365-.136.737-.177,1.13a1.675,1.675,0,0,0,1.579,2.079c1.235.16,1.779-.976,1.944-1.635a8.594,8.594,0,0,0,.2-1.35c-.2.005-.4.009-.606.009A18.258,18.258,0,0,1,9.236,12.767Z"/>
+</svg>
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -379,16 +379,20 @@ button > hbox > label {
line-height: 30px;
}
#allowSmartSize {
margin-top: 0;
margin-bottom: 4px;
}
+#trackingProtectionBox {
+ margin-top: 16px;
+}
+
#doNotTrackLearnMoreBox {
margin-top: 32px;
}
#trackingProtectionAdvancedSettings {
margin-inline-start: 15px;
}
--- a/browser/themes/shared/incontentprefs/privacy.css
+++ b/browser/themes/shared/incontentprefs/privacy.css
@@ -1,12 +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/. */
+/* Permissions */
+
+.content-blocking-icon,
.permission-icon {
height: 20px;
width: 20px;
vertical-align: middle;
-moz-context-properties: fill;
fill: currentColor;
}
@@ -24,8 +27,108 @@
.desktop-notification-icon {
list-style-image: url(chrome://browser/skin/notification-icons/desktop-notification.svg);
}
.midi-icon {
list-style-image: url(chrome://browser/skin/notification-icons/midi.svg);
}
+
+/* Content Blocking */
+
+#contentBlockingLearnMore {
+ margin-top: 4px !important;
+}
+
+#contentBlockingCheckboxContainer {
+ margin: 16px 0;
+}
+
+#contentBlockingToggleLabel {
+ line-height: 34px;
+}
+
+#contentBlockingCheckbox {
+ visibility: collapse;
+}
+
+/* If shown, the button-box takes up some space that results
+ * in unwanted changes in right-hand margin when toggling
+ * this button. We just hide it since we don't need it. */
+#contentBlockingToggle > .button-box {
+ display: none;
+}
+
+#contentBlockingToggle {
+ -moz-appearance: none;
+ box-sizing: border-box;
+ min-width: 48px;
+ max-width: 48px;
+ min-height: 30px;
+ max-height: 30px;
+ border-radius: 20px;
+ background-color: #d7d7db;
+ border: 1px solid transparent;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ margin-inline-start: 1px;
+ margin-inline-end: 7px;
+ padding: 5px;
+ transition: padding .2s ease;
+}
+
+#contentBlockingToggle::before {
+ position: relative;
+ display: block;
+ content: "";
+ width: 18px;
+ height: 18px;
+ border-radius: 10px;
+ background: white;
+}
+
+#contentBlockingCheckbox[checked="true"] + #contentBlockingToggle {
+ background-color: #2292d0;
+ border: 1px solid #2292d0;
+ /* Push the toggle to the right. */
+ padding-inline-start: 23px;
+}
+
+#contentBlockingToggle:hover,
+#contentBlockingToggle:-moz-focusring {
+ border: 1px solid #b1b1b3;
+}
+
+#contentBlockingCheckbox[checked] + #contentBlockingToggle:hover,
+#contentBlockingCheckbox[checked] + #contentBlockingToggle:-moz-focusring {
+ background-color: #0a84ff;
+}
+
+.content-blocking-category {
+ margin: 8px 0;
+}
+
+.content-blocking-category-icon {
+ padding: 4px;
+}
+
+.content-blocking-category-labels {
+ padding-inline-start: 4px;
+}
+
+#changeBlockListLink {
+ font-size: 90%;
+}
+
+.content-blocking-category-description {
+ font-size: 90%;
+ opacity: 0.6;
+}
+
+.content-blocking-category-menu {
+ margin-top: -2px;
+ min-width: 250px;
+}
+
+.tracking-protection-icon {
+ list-style-image: url(chrome://browser/skin/controlcenter/trackers.svg);
+}
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -22,16 +22,17 @@
skin/classic/browser/addons/addon-install-error.svg (../shared/addons/addon-install-error.svg)
skin/classic/browser/addons/addon-install-installed.svg (../shared/addons/addon-install-installed.svg)
skin/classic/browser/addons/addon-install-warning.svg (../shared/addons/addon-install-warning.svg)
skin/classic/browser/controlcenter/conn-not-secure.svg (../shared/controlcenter/conn-not-secure.svg)
skin/classic/browser/controlcenter/connection.svg (../shared/controlcenter/connection.svg)
skin/classic/browser/controlcenter/mcb-disabled.svg (../shared/controlcenter/mcb-disabled.svg)
skin/classic/browser/controlcenter/extension.svg (../shared/controlcenter/extension.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
+ skin/classic/browser/controlcenter/trackers.svg (../shared/controlcenter/trackers.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/tracking-protection-disabled.svg (../shared/controlcenter/tracking-protection-disabled.svg)
skin/classic/browser/controlcenter/warning-gray.svg (../shared/controlcenter/warning-gray.svg)
skin/classic/browser/controlcenter/warning-yellow.svg (../shared/controlcenter/warning-yellow.svg)
skin/classic/browser/customizableui/empty-overflow-panel.png (../shared/customizableui/empty-overflow-panel.png)
skin/classic/browser/customizableui/empty-overflow-panel@2x.png (../shared/customizableui/empty-overflow-panel@2x.png)
skin/classic/browser/customizableui/density-compact.svg (../shared/customizableui/density-compact.svg)
skin/classic/browser/customizableui/density-normal.svg (../shared/customizableui/density-normal.svg)