Bug 1397100 - Disable container about:preference checkbox if a container addon is enabled. r?felipc r?bsilverberg
MozReview-Commit-ID: DtJX3FiE0e0
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1533,16 +1533,17 @@ pref("privacy.userContext.longPressBehav
#else
pref("privacy.userContext.enabled", false);
pref("privacy.userContext.ui.enabled", false);
pref("privacy.usercontext.about_newtab_segregation.enabled", false);
// 0 disables long press, 1 when clicked, the menu is shown, 2 the menu is shown after X milliseconds.
pref("privacy.userContext.longPressBehavior", 0);
#endif
+pref("privacy.userContext.extension", "");
// Start the browser in e10s mode
pref("browser.tabs.remote.autostart", false);
pref("browser.tabs.remote.desktopbehavior", true);
#if !defined(RELEASE_OR_BETA) || defined(MOZ_DEV_EDITION)
// At the moment, autostart.2 is used, while autostart.1 is unused.
// We leave it here set to false to reset users' defaults and allow
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -29,16 +29,19 @@ const TYPE_MAYBE_VIDEO_FEED = "applicati
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
const TYPE_PDF = "application/pdf";
const PREF_PDFJS_DISABLED = "pdfjs.disabled";
const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types";
+// Pref for when containers is being controlled
+const PREF_CONTAINERS_EXTENSION = "privacy.userContext.extension";
+
// Preferences that affect which entries to show in the list.
const PREF_SHOW_PLUGINS_IN_LIST = "browser.download.show_plugins_in_list";
const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
"browser.download.hide_plugins_without_extensions";
/*
* Preferences where we store handling information about the feed type.
*
@@ -238,16 +241,18 @@ var gMainPane = {
setEventListener("useCurrent", "command",
gMainPane.setHomePageToCurrent);
setEventListener("useBookmark", "command",
gMainPane.setHomePageToBookmark);
setEventListener("restoreDefaultHomePage", "command",
gMainPane.restoreDefaultHomePage);
setEventListener("disableHomePageExtension", "command",
gMainPane.makeDisableControllingExtension("homepage_override"));
+ setEventListener("disableContainersExtension", "command",
+ gMainPane.makeDisableControllingExtension("privacy.containers"));
setEventListener("chooseLanguage", "command",
gMainPane.showLanguages);
setEventListener("translationAttributionImage", "click",
gMainPane.openTranslationProviderAttribution);
setEventListener("translateButton", "command",
gMainPane.showTranslationExceptions);
setEventListener("font.language.group", "change",
gMainPane._rebuildFonts);
@@ -459,35 +464,60 @@ var gMainPane = {
]);
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded");
},
+ // CONTAINERS
+
+ /*
+ * preferences:
+ *
+ * privacy.userContext.enabled
+ * - true if containers is enabled
+ */
+
+ /**
+ * Enables/disables the Settings button used to configure containers
+ */
+ readBrowserContainersCheckbox() {
+ const pref = document.getElementById("privacy.userContext.enabled");
+ const settings = document.getElementById("browserContainersSettings");
+
+ settings.disabled = !pref.value;
+ const containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
+ const containersCheckbox = document.getElementById("browserContainersCheckbox");
+ containersCheckbox.checked = containersEnabled;
+ handleControllingExtension("privacy.containers")
+ .then((isControlled) => {
+ containersCheckbox.disabled = isControlled;
+ });
+ },
+
/**
* Show the Containers UI depending on the privacy.userContext.ui.enabled pref.
*/
initBrowserContainers() {
if (!Services.prefs.getBoolPref("privacy.userContext.ui.enabled")) {
// The browserContainersGroup element has its own internal padding that
// is visible even if the browserContainersbox is visible, so hide the whole
// groupbox if the feature is disabled to prevent a gap in the preferences.
document.getElementById("browserContainersbox").setAttribute("data-hidden-from-search", "true");
return;
}
-
- let link = document.getElementById("browserContainersLearnMore");
+ this._prefSvc.addObserver(PREF_CONTAINERS_EXTENSION, this);
+
+ const link = document.getElementById("browserContainersLearnMore");
link.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "containers";
document.getElementById("browserContainersbox").hidden = false;
-
- document.getElementById("browserContainersCheckbox").checked =
- Services.prefs.getBoolPref("privacy.userContext.enabled");
+ this.readBrowserContainersCheckbox();
},
isE10SEnabled() {
let e10sEnabled;
try {
let e10sStatus = Components.classes["@mozilla.org/supports-PRUint64;1"]
.createInstance(Ci.nsISupportsPRUint64);
let appinfo = Services.appinfo.QueryInterface(Ci.nsIObserver);
@@ -1342,16 +1372,18 @@ var gMainPane = {
this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_WEB, this);
this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
+
+ this._prefSvc.removeObserver(PREF_CONTAINERS_EXTENSION, this);
},
// nsISupports
QueryInterface(aIID) {
if (aIID.equals(Ci.nsIObserver) ||
aIID.equals(Ci.nsIDOMEventListener ||
@@ -1361,16 +1393,20 @@ var gMainPane = {
throw Cr.NS_ERROR_NO_INTERFACE;
},
// nsIObserver
observe(aSubject, aTopic, aData) {
if (aTopic == "nsPref:changed") {
+ if (aData == PREF_CONTAINERS_EXTENSION) {
+ this.readBrowserContainersCheckbox();
+ return;
+ }
// Rebuild the list when there are changes to preferences that influence
// whether or not to show certain entries in the list.
if (!this._storingAction) {
// These two prefs alter the list of visible types, so we have to rebuild
// that list when they change.
if (aData == PREF_SHOW_PLUGINS_IN_LIST ||
aData == PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS) {
this._rebuildVisibleTypes();
@@ -2599,16 +2635,17 @@ function getLocalHandlerApp(aFile) {
createInstance(Ci.nsILocalHandlerApp);
localHandlerApp.name = getFileDisplayName(aFile);
localHandlerApp.executable = aFile;
return localHandlerApp;
}
let extensionControlledContentIds = {
+ "privacy.containers": "browserContainersExtensionContent",
"homepage_override": "browserHomePageExtensionContent",
};
/**
* Check if a pref is being managed by an extension.
*/
function getControllingExtensionId(settingName) {
return ExtensionPreferencesManager.getControllingExtensionId(settingName);
@@ -2627,17 +2664,17 @@ async function handleControllingExtensio
hideControllingExtension(prefName);
}
return !!controllingExtensionId;
}
async function showControllingExtension(settingName, extensionId) {
let extensionControlledContent = getControllingExtensionEl(settingName);
- // Tell the user what extension is controlling the homepage.
+ // Tell the user what extension is controlling the setting.
let addon = await AddonManager.getAddonByID(extensionId);
const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
let stringParts = document
.getElementById("bundlePreferences")
.getString(`extensionControlled.${settingName}`)
.split("%S");
let description = extensionControlledContent.querySelector("description");
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -419,37 +419,45 @@
preference="browser.tabs.loadInBackground"/>
#ifdef XP_WIN
<checkbox id="showTabsInTaskbar" label="&showTabsInTaskbar.label;"
accesskey="&showTabsInTaskbar.accesskey;"
preference="browser.taskbar.previews.enable"/>
#endif
- <hbox id="browserContainersbox" hidden="true" align="center">
- <checkbox id="browserContainersCheckbox"
- label="&browserContainersEnabled.label;"
- accesskey="&browserContainersEnabled.accesskey;"
- preference="privacy.userContext.enabled"
- onsyncfrompreference="return gPrivacyPane.readBrowserContainersCheckbox();"/>
- <label id="browserContainersLearnMore" class="learnMore text-link">
- &browserContainersLearnMore.label;
- </label>
- <spacer flex="1"/>
- <!-- 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="browserContainersSettings"
- class="accessory-button"
- label="&browserContainersSettings.label;"
- accesskey="&browserContainersSettings.accesskey;"
- searchkeywords="&addButton.label;
- &preferencesButton.label;
- &removeButton.label;"/>
+ <vbox id="browserContainersbox" hidden="true">
+ <hbox id="browserContainersExtensionContent" align="center">
+ <description control="disableContainersExtension" flex="1" />
+ <button id="disableContainersExtension"
+ class="extension-controlled-button accessory-button"
+ label="&disableExtension.label;" />
</hbox>
- </hbox>
+ <hbox align="center">
+ <checkbox id="browserContainersCheckbox"
+ label="&browserContainersEnabled.label;"
+ accesskey="&browserContainersEnabled.accesskey;"
+ preference="privacy.userContext.enabled"
+ onsyncfrompreference="return gMainPane.readBrowserContainersCheckbox();"/>
+ <label id="browserContainersLearnMore" class="learnMore text-link">
+ &browserContainersLearnMore.label;
+ </label>
+ <spacer flex="1"/>
+ <!-- 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="browserContainersSettings"
+ class="accessory-button"
+ label="&browserContainersSettings.label;"
+ accesskey="&browserContainersSettings.accesskey;"
+ searchkeywords="&addButton.label;
+ &preferencesButton.label;
+ &removeButton.label;"/>
+ </hbox>
+ </hbox>
+ </vbox>
</groupbox>
<hbox id="languageAndAppearanceCategory"
class="subcategory"
hidden="true"
data-category="paneGeneral">
<label class="header-name" flex="1">&languageAndAppearance.label;</label>
</hbox>
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -804,35 +804,16 @@ var gPrivacyPane = {
*/
_updateSanitizeSettingsButton() {
var settingsButton = document.getElementById("clearDataSettings");
var sanitizeOnShutdownPref = document.getElementById("privacy.sanitize.sanitizeOnShutdown");
settingsButton.disabled = !sanitizeOnShutdownPref.value;
},
- // CONTAINERS
-
- /*
- * preferences:
- *
- * privacy.userContext.enabled
- * - true if containers is enabled
- */
-
- /**
- * Enables/disables the Settings button used to configure containers
- */
- readBrowserContainersCheckbox() {
- var pref = document.getElementById("privacy.userContext.enabled");
- var settings = document.getElementById("browserContainersSettings");
-
- settings.disabled = !pref.value;
- },
-
toggleDoNotDisturbNotifications(event) {
AlertsServiceDND.manualDoNotDisturb = event.target.checked;
},
// GEOLOCATION
/**
* Displays the location exceptions dialog where specific site location
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -276,8 +276,13 @@ searchResults.sorryMessageUnix=Sorry! There are no results in Preferences for ā%Sā.
searchResults.needHelp2=Need help? Visit <html:a id="need-help-link" target="_blank" href="%1$S">%2$S Support</html:a>
# LOCALIZATION NOTE %S is the default value of the `dom.ipc.processCount` pref.
defaultContentProcessCount=%S (default)
# LOCALIZATION NOTE (extensionControlled.homepage_override):
# This string is shown to notify the user that their home page is being controlled by an extension.
extensionControlled.homepage_override = An extension, %S, controls your home page.
+
+# LOCALIZATION NOTE (extensionControlled.privacy.containers):
+# This string is shown to notify the user that Container Tabs are being enabled by an extension
+# %S is the container addon controlling it
+extensionControlled.privacy.containers = An extension, %S, requires Container Tabs.
\ No newline at end of file
--- a/toolkit/components/extensions/ext-contextualIdentities.js
+++ b/toolkit/components/extensions/ext-contextualIdentities.js
@@ -14,16 +14,17 @@ var {
ExtensionError,
} = ExtensionUtils;
const CONTAINER_PREF_INSTALL_DEFAULTS = {
"privacy.userContext.enabled": true,
"privacy.userContext.longPressBehavior": 2,
"privacy.userContext.ui.enabled": true,
"privacy.usercontext.about_newtab_segregation.enabled": true,
+ "privacy.userContext.extension": undefined,
};
const CONTAINERS_ENABLED_SETTING_NAME = "privacy.containers";
const CONTAINER_COLORS = new Map([
["blue", "#37adff"],
["turquoise", "#00c79a"],
["green", "#51cd00"],
@@ -103,34 +104,36 @@ const convertIdentityFromObserver = wrap
return result;
};
ExtensionPreferencesManager.addSetting(CONTAINERS_ENABLED_SETTING_NAME, {
prefNames: Object.keys(CONTAINER_PREF_INSTALL_DEFAULTS),
setCallback(value) {
- if (value === true) {
- return CONTAINER_PREF_INSTALL_DEFAULTS;
+ if (value !== true) {
+ return Object.assign(CONTAINER_PREF_INSTALL_DEFAULTS, {
+ "privacy.userContext.extension": value,
+ });
}
let prefs = {};
for (let pref of this.prefNames) {
prefs[pref] = undefined;
}
return prefs;
},
});
this.contextualIdentities = class extends ExtensionAPI {
onStartup() {
let {extension} = this;
if (extension.hasPermission("contextualIdentities")) {
- ExtensionPreferencesManager.setSetting(extension, CONTAINERS_ENABLED_SETTING_NAME, true);
+ ExtensionPreferencesManager.setSetting(extension, CONTAINERS_ENABLED_SETTING_NAME, extension.id);
}
}
getAPI(context) {
let self = {
contextualIdentities: {
async get(cookieStoreId) {
checkAPIEnabled();