Bug 1323395 - Show warning when disk space available for firefox is not enough, r=jaws
MozReview-Commit-ID: HttJ2RFCTtS
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -426,16 +426,91 @@ const gSessionHistoryObserver = {
// Hide session restore button on about:home
window.messageManager.broadcastAsyncMessage("Browser:HideSessionRestoreButton");
// Clear undo history of the URL bar
gURLBar.editor.transactionManager.clear()
}
};
+const gStoragePressureObserver = {
+ _lastNotificationTime: -1,
+
+ observe(subject, topic, data) {
+ if (topic != "QuotaManager::StoragePressure" ||
+ !Services.prefs.getBoolPref("browser.storageManager.enabled")) {
+ return;
+ }
+
+ // Don't display notification twice within the given interval.
+ // This is because
+ // - not to annoy user
+ // - give user some time to clean space.
+ // Even user sees notification and starts acting, it still takes some time.
+ const MIN_NOTIFICATION_INTERVAL_MS =
+ Services.prefs.getIntPref("browser.storageManager.pressureNotification.minIntervalMS");
+ let duration = Date.now() - this._lastNotificationTime;
+ if (duration <= MIN_NOTIFICATION_INTERVAL_MS) {
+ return;
+ }
+ this._lastNotificationTime = Date.now();
+
+ const BYTES_IN_GIGABYTE = 1073741824;
+ const USAGE_THRESHOLD_BYTES = BYTES_IN_GIGABYTE *
+ Services.prefs.getIntPref("browser.storageManager.pressureNotification.usageThresholdGB");
+ let msg = "";
+ let buttons = [];
+ let usage = parseInt(data);
+ let prefStrBundle = document.getElementById("bundle_preferences");
+ let notificationBox = document.getElementById("high-priority-global-notificationbox");
+ buttons.push({
+ label: prefStrBundle.getString("spaceAlert.learnMoreButton.label"),
+ accessKey: prefStrBundle.getString("spaceAlert.learnMoreButton.accesskey"),
+ callback(notificationBar, button) {
+ let learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
+ gBrowser.selectedTab = gBrowser.addTab(learnMoreURL);
+ }
+ });
+ if (usage < USAGE_THRESHOLD_BYTES) {
+ // The firefox-used space < 5GB, then warn user to free some disk space.
+ // This is because this usage is small and not the main cause for space issue.
+ // In order to avoid the bad and wrong impression among users that
+ // firefox eats disk space a lot, indicate users to clean up other disk space.
+ msg = prefStrBundle.getString("spaceAlert.under5GB.description");
+ buttons.push({
+ label: prefStrBundle.getString("spaceAlert.under5GB.okButton.label"),
+ accessKey: prefStrBundle.getString("spaceAlert.under5GB.okButton.accesskey"),
+ callback() {}
+ });
+ } else {
+ // The firefox-used space >= 5GB, then guide users to about:preferences
+ // to clear some data stored on firefox by websites.
+ let descriptionStringID = "spaceAlert.over5GB.description";
+ let prefButtonLabelStringID = "spaceAlert.over5GB.prefButton.label";
+ let prefButtonAccesskeyStringID = "spaceAlert.over5GB.prefButton.accesskey";
+ if (AppConstants.platform == "win") {
+ descriptionStringID = "spaceAlert.over5GB.descriptionWin";
+ prefButtonLabelStringID = "spaceAlert.over5GB.prefButtonWin.label";
+ prefButtonAccesskeyStringID = "spaceAlert.over5GB.prefButtonWin.accesskey";
+ }
+ msg = prefStrBundle.getString(descriptionStringID);
+ buttons.push({
+ label: prefStrBundle.getString(prefButtonLabelStringID),
+ accessKey: prefStrBundle.getString(prefButtonAccesskeyStringID),
+ callback(notificationBar, button) {
+ gBrowser.ownerGlobal.openPreferences("advanced", { advancedTab: "networkTab" });
+ }
+ });
+ }
+
+ notificationBox.appendNotification(
+ msg, "storage-pressure-notification", null, notificationBox.PRIORITY_WARNING_HIGH, buttons, null);
+ }
+};
+
/**
* Given a starting docshell and a URI to look up, find the docshell the URI
* is loaded in.
* @param aDocument
* A document to find instead of using just a URI - this is more specific.
* @param aDocShell
* The doc shell to start at
* @param aSoughtURI
@@ -1265,16 +1340,17 @@ var gBrowserInit = {
}
}
// Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
setTimeout(function() { SafeBrowsing.init(); }, 2000);
Services.obs.addObserver(gIdentityHandler, "perm-changed", false);
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
+ Services.obs.addObserver(gStoragePressureObserver, "QuotaManager::StoragePressure", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-disabled", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-started", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-origin-blocked", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-confirmation", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
@@ -1599,16 +1675,17 @@ var gBrowserInit = {
gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
ctrlTab.uninit();
SocialUI.uninit();
gBrowserThumbnails.uninit();
FullZoom.destroy();
Services.obs.removeObserver(gIdentityHandler, "perm-changed");
Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
+ Services.obs.removeObserver(gStoragePressureObserver, "QuotaManager::StoragePressure");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-disabled");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-started");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-origin-blocked");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-confirmation");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
window.messageManager.removeMessageListener("Browser:URIFixup", gKeywordURIFixup);
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -338,16 +338,17 @@ skip-if = e10s && debug && os == "win" #
support-files =
contentSearchUI.html
contentSearchUI.js
[browser_selectpopup.js]
skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux builds
[browser_selectTabAtIndex.js]
[browser_ssl_error_reports.js]
[browser_star_hsts.js]
+[browser_storagePressure_notification.js]
[browser_subframe_favicons_not_used.js]
[browser_syncui.js]
skip-if = os == 'linux' # Bug 1304272
[browser_tab_close_dependent_window.js]
[browser_tabDrop.js]
[browser_tabReorder.js]
[browser_tab_detach_restore.js]
[browser_tab_drag_drop_perwindow.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_storagePressure_notification.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function notifyStoragePressure(usage = 100) {
+ let notifyPromise = TestUtils.topicObserved("QuotaManager::StoragePressure", () => true);
+ Services.obs.notifyObservers(null, "QuotaManager::StoragePressure", usage);
+ return notifyPromise;
+}
+
+function advancedAboutPrefPromise() {
+ let promises = [
+ BrowserTestUtils.waitForLocationChange(gBrowser, "about:preferences#advanced"),
+ TestUtils.topicObserved("advanced-pane-loaded", () => true)
+ ];
+ return Promise.all(promises);
+}
+
+// Test only displaying notification once within the given interval
+add_task(function* () {
+ const TEST_NOTIFICATION_INTERVAL_MS = 2000;
+ yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
+ yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.pressureNotification.minIntervalMS", TEST_NOTIFICATION_INTERVAL_MS]]});
+
+ yield notifyStoragePressure();
+ let notificationbox = document.getElementById("high-priority-global-notificationbox");
+ let notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+ ok(notification instanceof XULElement, "Should display storage pressure notification");
+ notification.close();
+
+ yield notifyStoragePressure();
+ notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+ is(notification, null, "Should not display storage pressure notification more than once within the given interval");
+
+ yield new Promise(resolve => setTimeout(resolve, TEST_NOTIFICATION_INTERVAL_MS + 1));
+ yield notifyStoragePressure();
+ notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+ ok(notification instanceof XULElement, "Should display storage pressure notification after the given interval");
+ notification.close();
+});
+
+// Test guiding user to about:preferences when usage exceeds the given threshold
+add_task(function* () {
+ yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
+ yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.pressureNotification.minIntervalMS", 0]]});
+
+ const BYTES_IN_GIGABYTE = 1073741824;
+ const USAGE_THRESHOLD_BYTES = BYTES_IN_GIGABYTE *
+ Services.prefs.getIntPref("browser.storageManager.pressureNotification.usageThresholdGB");
+ yield notifyStoragePressure(USAGE_THRESHOLD_BYTES);
+ let notificationbox = document.getElementById("high-priority-global-notificationbox");
+ let notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+ ok(notification instanceof XULElement, "Should display storage pressure notification");
+
+ let prefBtn = notification.getElementsByTagName("button")[1];
+ let aboutPrefPromise = advancedAboutPrefPromise();
+ prefBtn.doCommand();
+ yield aboutPrefPromise;
+ let prefDoc = gBrowser.selectedBrowser.contentDocument;
+ let advancedPrefs = prefDoc.getElementById("advancedPrefs");
+ is(advancedPrefs.selectedIndex, 2, "Should open the Network tab in about:preferences#advanced");
+});
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -195,16 +195,29 @@ siteUsage=%1$S %2$S
# never displayed together and can share the same accesskey.
# When only partial sites are shown as a result of keyword search,
# removeAllShown is displayed as button label.
# removeAll is displayed when no keyword search and all sites are shown.
removeAllSiteData.label=Remove All
removeAllSiteData.accesskey=e
removeAllSiteDataShown.label=Remove All Shown
removeAllSiteDataShown.accesskey=e
+spaceAlert.learnMoreButton.label=Learn More
+spaceAlert.learnMoreButton.accesskey=L
+spaceAlert.over5GB.prefButton.label=Open Preferences
+spaceAlert.over5GB.prefButton.accesskey=O
+# LOCALIZATION NOTE (spaceAlert.over5GB.prefButtonWin.label): On Windows Preferences is called Options
+spaceAlert.over5GB.prefButtonWin.label=Open Options
+spaceAlert.over5GB.prefButtonWin.accesskey=O
+spaceAlert.over5GB.description=Firefox is running out of disk space. Website contents may not display properly. You can clear stored site data in Preferences > Advanced > Site Data.
+# LOCALIZATION NOTE (spaceAlert.over5GB.descriptionWin): On Windows Preferences is called Options
+spaceAlert.over5GB.descriptionWin=Firefox is running out of disk space. Website contents may not display properly. You can clear stored site data in Options > Advanced > Site Data.
+spaceAlert.under5GB.okButton.label=OK, Got it
+spaceAlert.under5GB.okButton.accesskey=K
+spaceAlert.under5GB.description=Firefox is running out of disk space. Website contents may not display properly. Visit “Learn More” to optimize your disk usage for better browsing experience.
# LOCALIZATION NOTE (featureEnableRequiresRestart, featureDisableRequiresRestart, restartTitle): %S = brandShortName
featureEnableRequiresRestart=%S must restart to enable this feature.
featureDisableRequiresRestart=%S must restart to disable this feature.
shouldRestartTitle=Restart %S
okToRestartButton=Restart %S now
revertNoRestartButton=Revert
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5581,16 +5581,18 @@ pref("dom.storageManager.enabled", false
// a single web page in a row, all following authentication dialogs will
// be blocked (automatically canceled) for that page. The counter resets
// when the page is reloaded. To turn this feature off, just set the limit to 0.
pref("prompts.authentication_dialog_abuse_limit", 3);
// Enable the Storage management in about:preferences and persistent-storage permission request
// To enable the DOM implementation, turn on "dom.storageManager.enabled"
pref("browser.storageManager.enabled", false);
+pref("browser.storageManager.pressureNotification.minIntervalMS", 1200000);
+pref("browser.storageManager.pressureNotification.usageThresholdGB", 5);
pref("dom.IntersectionObserver.enabled", false);
// Whether module scripts (<script type="module">) are enabled for content.
pref("dom.moduleScripts.enabled", false);
#ifdef FUZZING
pref("fuzzing.enabled", false);
#endif