author | Robert Strong <robert.bugzilla@gmail.com> |
Tue, 06 Apr 2010 19:49:23 -0700 | |
changeset 40527 | 9996ac775114cd3dcef81c9095772f5cf0132c16 |
parent 40526 | 8e6ef255d9d6a9cf369af9a8aa60a2378441cb30 |
child 40528 | 8722c089c3e6ac924aab59828f01306927fbf286 |
push id | 12649 |
push user | rstrong@mozilla.com |
push date | Wed, 07 Apr 2010 02:50:17 +0000 |
treeherder | mozilla-central@e0321787e483 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dietrich, dtownsend, gavin, beltzner |
bugs | 538331 |
milestone | 1.9.3a4pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
|
--- a/browser/components/Makefile.in +++ b/browser/components/Makefile.in @@ -80,15 +80,19 @@ ifndef WINCE PARALLEL_DIRS += wintaskbar endif endif ifdef MOZ_SAFE_BROWSING PARALLEL_DIRS += safebrowsing endif +ifdef ENABLE_TESTS +DIRS += test +endif + DIRS += build ifdef MOZILLA_OFFICIAL DEFINES += -DOFFICIAL_BUILD=1 endif include $(topsrcdir)/config/rules.mk
--- a/browser/components/nsBrowserContentHandler.js +++ b/browser/components/nsBrowserContentHandler.js @@ -15,16 +15,17 @@ # # The Initial Developer of the Original Code is # Benjamin Smedberg <benjamin@smedbergs.us> # # Portions created by the Initial Developer are Copyright (C) 2004 # the Initial Developer. All Rights Reserved. # # Contributor(s): +# Robert Strong <robert.bugzilla@gmail.com> # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your @@ -144,16 +145,50 @@ function needHomepageOverride(prefb) { prefb.setCharPref("browser.startup.homepage_override.mstone", mstone); return (savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE); } return OVERRIDE_NONE; } +/** + * Gets the override page for the first run after the application has been + * updated. + * @param defaultOverridePage + * The default override page. + * @return The override page. + */ +function getPostUpdateOverridePage(defaultOverridePage) { + var um = Components.classes["@mozilla.org/updates/update-manager;1"] + .getService(Components.interfaces.nsIUpdateManager); + try { + // If the updates.xml file is deleted then getUpdateAt will throw. + var update = um.getUpdateAt(0) + .QueryInterface(Components.interfaces.nsIPropertyBag); + } catch (e) { + // This should never happen. + Components.utils.reportError("Unable to find update: " + e); + return defaultOverridePage; + } + + let actions = update.getProperty("actions"); + // When the update doesn't specify actions fallback to the original behavior + // of displaying the default override page. + if (!actions) + return defaultOverridePage; + + // The existence of silent or the non-existence of showURL in the actions both + // mean that an override page should not be displayed. + if (actions.indexOf("silent") != -1 || actions.indexOf("showURL") == -1) + return ""; + + return update.getProperty("openURL") || defaultOverridePage; +} + // Copies a pref override file into the user's profile pref-override folder, // and then tells the pref service to reload its default prefs. function copyPrefOverride() { try { var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties); const NS_APP_EXISTING_PREF_OVERRIDE = "ExistingPrefOverride"; var prefOverride = fileLocator.get(NS_APP_EXISTING_PREF_OVERRIDE, @@ -531,18 +566,20 @@ var nsBrowserContentHandler = { copyPrefOverride(); // Check whether we have a session to restore. If we do, we assume // that this is an "update" session. var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"] .getService(Components.interfaces.nsISessionStartup); haveUpdateSession = ss.doRestore(); overridePage = formatter.formatURLPref("startup.homepage_override_url"); + if (prefb.prefHasUserValue("app.update.postupdate")) + overridePage = getPostUpdateOverridePage(overridePage); break; - } + } } catch (ex) {} // formatURLPref might return "about:blank" if getting the pref fails if (overridePage == "about:blank") overridePage = ""; var startPage = ""; try {
--- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -21,16 +21,17 @@ # Contributor(s): # Giorgio Maone <g.maone@informaction.com> # Seth Spitzer <sspitzer@mozilla.com> # Asaf Romano <mano@mozilla.com> # Marco Bonardo <mak77@bonardo.net> # Dietrich Ayala <dietrich@mozilla.com> # Ehsan Akhgari <ehsan.akhgari@gmail.com> # Nils Maier <maierman@web.de> +# Robert Strong <robert.bugzilla@gmail.com> # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your @@ -212,16 +213,23 @@ BrowserGlue.prototype = { break; case "bookmarks-restore-success": case "bookmarks-restore-failed": this._observerService.removeObserver(this, "bookmarks-restore-success"); this._observerService.removeObserver(this, "bookmarks-restore-failed"); if (topic == "bookmarks-restore-success" && data == "html-initial") this.ensurePlacesDefaultQueriesInitialized(); break; + case "browser-glue-test": // used by tests + if (data == "post-update-notification") { + if (this._prefs.prefHasUserValue("app.update.postupdate")) + this._showUpdateNotification(); + break; + } + break; } }, // initialization (called on application startup) _init: function BG__init() { // observer registration const osvr = this._observerService; osvr.addObserver(this, "xpcom-shutdown", false); @@ -334,16 +342,20 @@ BrowserGlue.prototype = { }, // Browser startup complete. All initial windows have opened. _onBrowserStartup: function BG__onBrowserStartup() { // Show about:rights notification, if needed. if (this._shouldShowRights()) this._showRightsNotification(); + // Show update notification, if needed. + if (this._prefs.prefHasUserValue("app.update.postupdate")) + this._showUpdateNotification(); + // If new add-ons were installed during startup open the add-ons manager. if (this._prefs.prefHasUserValue(PREF_EM_NEW_ADDONS_LIST)) { var args = Cc["@mozilla.org/supports-array;1"]. createInstance(Ci.nsISupportsArray); var str = Cc["@mozilla.org/supports-string;1"]. createInstance(Ci.nsISupportsString); str.data = ""; args.AppendElement(str); @@ -571,17 +583,133 @@ BrowserGlue.prototype = { // Set pref to indicate we've shown the notification. var currentVersion = this._prefs.getIntPref("browser.rights.version"); this._prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true); var box = notifyBox.appendNotification(notifyRightsText, "about-rights", null, notifyBox.PRIORITY_INFO_LOW, buttons); box.persistence = 3; // arbitrary number, just so bar sticks around for a bit }, - + + _showUpdateNotification: function BG__showUpdateNotification() { + this._prefs.clearUserPref("app.update.postupdate"); + + var um = Cc["@mozilla.org/updates/update-manager;1"]. + getService(Ci.nsIUpdateManager); + try { + // If the updates.xml file is deleted then getUpdateAt will throw. + var update = um.getUpdateAt(0).QueryInterface(Ci.nsIPropertyBag); + } + catch (e) { + // This should never happen. + Cu.reportError("Unable to find update: " + e); + return; + } + + var actions = update.getProperty("actions"); + if (!actions || actions.indexOf("silent") != -1) + return; + + var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]. + getService(Ci.nsIURLFormatter); + var browserBundle = this._bundleService. + createBundle("chrome://browser/locale/browser.properties"); + var brandBundle = this._bundleService. + createBundle("chrome://branding/locale/brand.properties"); + var appName = brandBundle.GetStringFromName("brandShortName"); + + function getNotifyString(aPropData) { + var propValue = update.getProperty(aPropData.propName); + if (!propValue) { + if (aPropData.prefName) + propValue = formatter.formatURLPref(aPropData.prefName); + else if (aPropData.stringParams) + propValue = browserBundle.formatStringFromName(aPropData.stringName, + aPropData.stringParams, + aPropData.stringParams.length); + else + propValue = browserBundle.GetStringFromName(aPropData.stringName); + } + return propValue; + } + + if (actions.indexOf("showNotification") != -1) { + let text = getNotifyString({propName: "notificationText", + stringName: "puNotifyText", + stringParams: [appName]}); + let url = getNotifyString({propName: "notificationURL", + prefName: "startup.homepage_override_url"}); + let label = getNotifyString({propName: "notificationButtonLabel", + stringName: "pu.notifyButton.label"}); + let key = getNotifyString({propName: "notificationButtonAccessKey", + stringName: "pu.notifyButton.accesskey"}); + + let win = this.getMostRecentBrowserWindow(); + let browser = win.gBrowser; // for closure in notification bar callback + let notifyBox = browser.getNotificationBox(); + + let buttons = [ + { + label: label, + accessKey: key, + popup: null, + callback: function(aNotificationBar, aButton) { + browser.selectedTab = browser.addTab(url); + } + } + ]; + + let box = notifyBox.appendNotification(text, "post-update-notification", + null, notifyBox.PRIORITY_INFO_LOW, + buttons); + box.persistence = 3; + } + + if (actions.indexOf("showAlert") == -1) + return; + + let notifier; + try { + notifier = Cc["@mozilla.org/alerts-service;1"]. + getService(Ci.nsIAlertsService); + } + catch (e) { + // nsIAlertsService is not available for this platform + return; + } + + let title = getNotifyString({propName: "alertTitle", + stringName: "puAlertTitle", + stringParams: [appName]}); + let text = getNotifyString({propName: "alertText", + stringName: "puAlertText", + stringParams: [appName]}); + let url = getNotifyString({propName: "alertURL", + prefName: "startup.homepage_override_url"}); + + var self = this; + function clickCallback(subject, topic, data) { + // This callback will be called twice but only once with this topic + if (topic != "alertclickcallback") + return; + let win = self.getMostRecentBrowserWindow(); + let browser = win.gBrowser; + browser.selectedTab = browser.addTab(data); + } + + try { + // This will throw NS_ERROR_NOT_AVAILABLE if the notification cannot + // be displayed per the idl. + notifier.showAlertNotification("post-update-notification", title, text, + true, url, clickCallback); + } + catch (e) { + } + }, + _showPluginUpdatePage: function BG__showPluginUpdatePage() { this._prefs.setBoolPref(PREF_PLUGINS_NOTIFYUSER, false); var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]. getService(Ci.nsIURLFormatter); var updateUrl = formatter.formatURLPref(PREF_PLUGINS_UPDATEURL); var win = this.getMostRecentBrowserWindow();
new file mode 100644 --- /dev/null +++ b/browser/components/test/Makefile.in @@ -0,0 +1,48 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Robert Strong <robert.bugzilla@gmail.com> (Original Author) +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = browser + +include $(topsrcdir)/config/rules.mk
new file mode 100644 --- /dev/null +++ b/browser/components/test/browser/Makefile.in @@ -0,0 +1,52 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Robert Strong <robert.bugzilla@gmail.com> (Original Author) +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = browser/components/test/browser + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +_BROWSER_TEST_FILES = \ + browser_bug538331.js \ + $(NULL) + +libs:: $(_BROWSER_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/browser/components/test/browser/browser_bug538331.js @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const PREF_POSTUPDATE = "app.update.postupdate"; +const PREF_MSTONE = "browser.startup.homepage_override.mstone"; +const PREF_OVERRIDE_URL = "startup.homepage_override_url"; + +const DEFAULT_PREF_URL = "http://pref.example.com/"; +const DEFAULT_UPDATE_URL = "http://example.com/"; + +const XML_EMPTY = "<?xml version=\"1.0\"?><updates xmlns=" + + "\"http://www.mozilla.org/2005/app-update\"></updates>"; + +const XML_PREFIX = "<updates xmlns=\"http://www.mozilla.org/2005/app-update\"" + + "><update appVersion=\"1.0\" buildID=\"20080811053724\" " + + "channel=\"nightly\" displayVersion=\"Version 1.0\" " + + "extensionVersion=\"1.0\" installDate=\"1238441400314\" " + + "isCompleteUpdate=\"true\" name=\"Update Test 1.0\" " + + "serviceURL=\"https://example.com/\" showNeverForVersion=" + + "\"false\" showPrompt=\"false\" showSurvey=\"false\" type=" + + "\"minor\" version=\"version 1.0\" detailsURL=" + + "\"http://example.com/\" previousAppVersion=\"1.0\" " + + "statusText=\"The Update was successfully installed\" " + + "foregroundDownload=\"true\""; + +const XML_SUFFIX = "><patch type=\"complete\" URL=\"http://example.com/\" " + + "hashFunction=\"MD5\" hashValue=" + + "\"6232cd43a1c77e30191c53a329a3f99d\" size=\"775\" " + + "selected=\"true\" state=\"succeeded\"/></update></updates>"; + +// nsBrowserContentHandler.js defaultArgs tests +const BCH_TESTS = [ + { + description: "no mstone change and no update", + noPostUpdatePref: true, + noMstoneChange: true + }, { + description: "mstone changed and no update", + noPostUpdatePref: true, + prefURL: DEFAULT_PREF_URL + }, { + description: "no mstone change and update with 'showURL' for actions", + actions: "showURL", + noMstoneChange: true + }, { + description: "update without actions", + prefURL: DEFAULT_PREF_URL + }, { + description: "update with 'showURL' for actions", + actions: "showURL", + prefURL: DEFAULT_PREF_URL + }, { + description: "update with 'showURL' for actions and openURL", + actions: "showURL", + openURL: DEFAULT_UPDATE_URL + }, { + description: "update with 'showURL showAlert' for actions", + actions: "showAlert showURL", + prefURL: DEFAULT_PREF_URL + }, { + description: "update with 'showAlert showURL' for actions and openURL", + actions: "showAlert showURL", + openURL: DEFAULT_UPDATE_URL + }, { + description: "update with 'showURL showNotification' for actions", + actions: "showURL showNotification", + prefURL: DEFAULT_PREF_URL + }, { + description: "update with 'showNotification showURL' for actions and " + + "openURL", + actions: "showNotification showURL", + openURL: DEFAULT_UPDATE_URL + }, { + description: "update with 'showAlert showURL showNotification' for actions", + actions: "showAlert showURL showNotification", + prefURL: DEFAULT_PREF_URL + }, { + description: "update with 'showNotification showURL showAlert' for " + + "actions and openURL", + actions: "showNotification showURL showAlert", + openURL: DEFAULT_UPDATE_URL + }, { + description: "update with 'showAlert' for actions", + actions: "showAlert" + }, { + description: "update with 'showAlert showNotification' for actions", + actions: "showAlert showNotification" + }, { + description: "update with 'showNotification' for actions", + actions: "showNotification" + }, { + description: "update with 'showNotification showAlert' for actions", + actions: "showNotification showAlert" + }, { + description: "update with 'silent' for actions", + actions: "silent" + }, { + description: "update with 'silent showURL showAlert showNotification' " + + "for actions and openURL", + actions: "silent showURL showAlert showNotification" + } +]; + +var gOriginalMStone; +var gOriginalOverrideURL; + +__defineGetter__("gBG", function() { + delete this.gBG; + return this.gBG = Cc["@mozilla.org/browser/browserglue;1"]. + getService(Ci.nsIBrowserGlue). + QueryInterface(Ci.nsIObserver); +}); + +function test() +{ + waitForExplicitFinish(); + + if (gPrefService.prefHasUserValue(PREF_MSTONE)) { + gOriginalMStone = gPrefService.getCharPref(PREF_MSTONE); + } + + if (gPrefService.prefHasUserValue(PREF_OVERRIDE_URL)) { + gOriginalOverrideURL = gPrefService.getCharPref(PREF_OVERRIDE_URL); + } + + testDefaultArgs(); +} + +function finish_test() +{ + // Reset browser.startup.homepage_override.mstone to the original value or + // clear it if it didn't exist. + if (gOriginalMStone) { + gPrefService.setCharPref(PREF_MSTONE, gOriginalMStone); + } else if (gPrefService.prefHasUserValue(PREF_MSTONE)) { + gPrefService.clearUserPref(PREF_MSTONE); + } + + // Reset startup.homepage_override_url to the original value or clear it if + // it didn't exist. + if (gOriginalOverrideURL) { + gPrefService.setCharPref(PREF_OVERRIDE_URL, gOriginalOverrideURL); + } else if (gPrefService.prefHasUserValue(PREF_OVERRIDE_URL)) { + gPrefService.clearUserPref(PREF_OVERRIDE_URL); + } + + writeUpdatesToXMLFile(XML_EMPTY); + reloadUpdateManagerData(); + + finish(); +} + +// Test the defaultArgs returned by nsBrowserContentHandler after an update +function testDefaultArgs() +{ + // Clear any pre-existing override in defaultArgs that are hanging around. + // This will also set the browser.startup.homepage_override.mstone preference + // if it isn't already set. + Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs; + + let originalMstone = gPrefService.getCharPref(PREF_MSTONE); + + gPrefService.setCharPref(PREF_OVERRIDE_URL, DEFAULT_PREF_URL); + + writeUpdatesToXMLFile(XML_EMPTY); + reloadUpdateManagerData(); + + for (let i = 0; i < BCH_TESTS.length; i++) { + let test = BCH_TESTS[i]; + ok(true, "Test nsBrowserContentHandler " + (i + 1) + ": " + test.description); + + if (test.actions) { + let actionsXML = " actions=\"" + test.actions + "\""; + if (test.openURL) { + actionsXML += " openURL=\"" + test.openURL + "\""; + } + writeUpdatesToXMLFile(XML_PREFIX + actionsXML + XML_SUFFIX); + } else { + writeUpdatesToXMLFile(XML_EMPTY); + } + + reloadUpdateManagerData(); + + let noOverrideArgs = Cc["@mozilla.org/browser/clh;1"]. + getService(Ci.nsIBrowserHandler).defaultArgs; + + let overrideArgs = ""; + if (test.prefURL) { + overrideArgs = test.prefURL; + } else if (test.openURL) { + overrideArgs = test.openURL; + } + + if (overrideArgs == "" && noOverrideArgs) { + overrideArgs = noOverrideArgs; + } else if (noOverrideArgs) { + overrideArgs += "|" + noOverrideArgs; + } + + if (test.noMstoneChange === undefined) { + gPrefService.setCharPref(PREF_MSTONE, "PreviousMilestone"); + } + + if (test.noPostUpdatePref == undefined) { + gPrefService.setBoolPref(PREF_POSTUPDATE, true); + } + + let defaultArgs = Cc["@mozilla.org/browser/clh;1"]. + getService(Ci.nsIBrowserHandler).defaultArgs; + is(defaultArgs, overrideArgs, "correct value returned by defaultArgs"); + + if (test.noMstoneChange === undefined || test.noMstoneChange != true) { + let newMstone = gPrefService.getCharPref(PREF_MSTONE); + is(originalMstone, newMstone, "preference " + PREF_MSTONE + + " should have been updated"); + } + + if (gPrefService.prefHasUserValue(PREF_POSTUPDATE)) { + gPrefService.clearUserPref(PREF_POSTUPDATE); + } + } + + testShowNotification(); +} + +// nsBrowserGlue.js _showUpdateNotification notification tests +const BG_NOTIFY_TESTS = [ + { + description: "'silent showNotification' actions should not display a notification", + actions: "silent showNotification" + }, { + description: "'showNotification' for actions should display a notification", + actions: "showNotification" + }, { + description: "no actions and empty updates.xml", + }, { + description: "'showAlert' for actions should not display a notification", + actions: "showAlert" + }, { + // This test MUST be the last test in the array to test opening the url + // provided by the updates.xml. + description: "'showNotification' for actions with custom notification " + + "attributes should display a notification", + actions: "showNotification", + notificationText: "notification text", + notificationURL: DEFAULT_UPDATE_URL, + notificationButtonLabel: "button label", + notificationButtonAccessKey: "b" + } +]; + +// Test showing a notification after an update +// _showUpdateNotification in nsBrowserGlue.js +function testShowNotification() +{ + let gTestBrowser = gBrowser.selectedBrowser; + let notifyBox = gBrowser.getNotificationBox(gTestBrowser); + + for (let i = 0; i < BG_NOTIFY_TESTS.length; i++) { + let test = BG_NOTIFY_TESTS[i]; + ok(true, "Test showNotification " + (i + 1) + ": " + test.description); + + if (test.actions) { + let actionsXML = " actions=\"" + test.actions + "\""; + if (test.notificationText) { + actionsXML += " notificationText=\"" + test.notificationText + "\""; + } + if (test.notificationURL) { + actionsXML += " notificationURL=\"" + test.notificationURL + "\""; + } + if (test.notificationButtonLabel) { + actionsXML += " notificationButtonLabel=\"" + test.notificationButtonLabel + "\""; + } + if (test.notificationButtonAccessKey) { + actionsXML += " notificationButtonAccessKey=\"" + test.notificationButtonAccessKey + "\""; + } + writeUpdatesToXMLFile(XML_PREFIX + actionsXML + XML_SUFFIX); + } else { + writeUpdatesToXMLFile(XML_EMPTY); + } + + reloadUpdateManagerData(); + gPrefService.setBoolPref(PREF_POSTUPDATE, true); + + gBG.observe(null, "browser-glue-test", "post-update-notification"); + + let updateBox = notifyBox.getNotificationWithValue("post-update-notification"); + if (test.actions && test.actions.indexOf("showNotification") != -1 && + test.actions.indexOf("silent") == -1) { + ok(updateBox, "Update notification box should have been displayed"); + if (updateBox) { + if (test.notificationText) { + is(updateBox.label, test.notificationText, "Update notification box " + + "should have the label provided by the update"); + } + if (test.notificationButtonLabel) { + var button = updateBox.getElementsByTagName("button").item(0); + is(button.label, test.notificationButtonLabel, "Update notification " + + "box button should have the label provided by the update"); + if (test.notificationButtonAccessKey) { + let accessKey = button.getAttribute("accesskey"); + is(accessKey, test.notificationButtonAccessKey, "Update " + + "notification box button should have the accesskey " + + "provided by the update"); + } + } + // The last test opens an url and verifies the url from the updates.xml + // is correct. + if (i == (BG_NOTIFY_TESTS.length - 1)) { + button.click(); + gBrowser.selectedBrowser.addEventListener("load", testNotificationURL, true); + } + } else if (i == (BG_NOTIFY_TESTS.length - 1)) { + // If updateBox is null the test has already reported errors so bail + finish_test(); + } + notifyBox.removeAllNotifications(true); + } else { + ok(!updateBox, "Update notification box should not have been displayed"); + } + + let prefHasUserValue = gPrefService.prefHasUserValue(PREF_POSTUPDATE); + is(prefHasUserValue, false, "preference " + PREF_POSTUPDATE + + " shouldn't have a user value"); + } +} + +// Test opening the url provided by the updates.xml in the last test +function testNotificationURL() +{ + ok(true, "Test testNotificationURL: clicking the notification button " + + "opened the url specified by the update"); + let href = gBrowser.selectedBrowser.contentWindow.location.href; + let expectedURL = BG_NOTIFY_TESTS[BG_NOTIFY_TESTS.length - 1].notificationURL; + is(href, expectedURL, "The url opened from the notification should be the " + + "url provided by the update"); + gBrowser.removeCurrentTab(); + window.focus(); + finish_test(); +} + +/* Reloads the update metadata from disk */ +function reloadUpdateManagerData() +{ + Cc["@mozilla.org/updates/update-manager;1"].getService(Ci.nsIUpdateManager). + QueryInterface(Ci.nsIObserver).observe(null, "um-reload-update-data", ""); +} + + +function writeUpdatesToXMLFile(aText) +{ + const PERMS_FILE = 0644; + + const MODE_WRONLY = 0x02; + const MODE_CREATE = 0x08; + const MODE_TRUNCATE = 0x20; + + let file = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties). + get("XCurProcD", Ci.nsIFile); + file.append("updates.xml"); + let fos = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + if (!file.exists()) { + file.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + fos.init(file, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0); + fos.write(aText, aText.length); + fos.close(); +}
--- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -186,16 +186,24 @@ editBookmarkPanel.editBookmarkTitle=Edit # LOCALIZATION NOTE (editBookmark.removeBookmarks.label) # Semi-colon list of plural forms. Replacement for #1 is # the number of bookmarks to be removed. # If this causes problems with localization you can also do "Remove Bookmarks (#1)" # instead of "Remove #1 Bookmarks". editBookmark.removeBookmarks.label=Remove Bookmark;Remove #1 Bookmarks +# Post Update Notifications +pu.notifyButton.label=Details… +pu.notifyButton.accesskey=D +# LOCALIZATION NOTE %S will be replaced by the short name of the application. +puNotifyText=%S has been updated +puAlertTitle=%S Updated +puAlertText=Click here for details + # Geolocation UI # LOCALIZATION NOTE (geolocation.shareLocation geolocation.dontShareLocation): #If you're having trouble with the word Share, please use Allow and Block in your language. geolocation.shareLocation=Share Location geolocation.shareLocation.accesskey=a geolocation.dontShareLocation=Don't Share geolocation.dontShareLocation.accesskey=o