mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 600874 - Show restart notification for add-on updates [r=mfinkle]
This commit is contained in:
parent
2ade5ac2c5
commit
16806f811e
@ -764,7 +764,11 @@ AddonInstallListener.prototype = {
|
||||
_updating: false,
|
||||
|
||||
onInstallEnded: function(aInstall, aAddon) {
|
||||
// XXX fix updating stuff
|
||||
let element = ExtensionsView.getElementForAddon(aAddon.id);
|
||||
if (!element)
|
||||
return;
|
||||
|
||||
this._updating = element.hasAttribute("updating");
|
||||
if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL)
|
||||
ExtensionsView.showRestart(element.hasAttribute("updating") ? "update" : "normal");
|
||||
|
||||
@ -773,15 +777,11 @@ AddonInstallListener.prototype = {
|
||||
if (!ExtensionsView.visible)
|
||||
return;
|
||||
|
||||
let element = ExtensionsView.getElementForAddon(aInstall.sourceURI.spec);
|
||||
if (!element)
|
||||
return;
|
||||
|
||||
element.setAttribute("opType", "needs-restart");
|
||||
element.setAttribute("status", "success");
|
||||
|
||||
// If we are updating an add-on, change the status
|
||||
if (element.hasAttribute("updating")) {
|
||||
if (this._updating) {
|
||||
let strings = Elements.browserBundle;
|
||||
element.setAttribute("updateStatus", strings.getFormattedString("addonUpdate.updated", [aAddon.version]));
|
||||
element.removeAttribute("updating");
|
||||
|
@ -40,6 +40,8 @@ topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = mobile/chrome
|
||||
TESTXPI = $(CURDIR)/$(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)/addons
|
||||
ADDONSRC = $(srcdir)/addons
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@ -58,6 +60,7 @@ _BROWSER_FILES = \
|
||||
browser_click_content.js \
|
||||
browser_contacts.js \
|
||||
browser_find.js \
|
||||
browser_addons.js \
|
||||
browser_forms.html \
|
||||
browser_forms.js \
|
||||
browser_mainui.js \
|
||||
@ -77,7 +80,21 @@ _BROWSER_FILES = \
|
||||
browser_viewport.sjs \
|
||||
browser_no_title.html \
|
||||
browser_english_title.html \
|
||||
browser_install.xml \
|
||||
browser_upgrade.rdf\
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
||||
|
||||
libs::
|
||||
rm -rf $(TESTXPI)
|
||||
$(NSINSTALL) -D $(TESTXPI)
|
||||
if [ -d $(ADDONSRC) ]; then \
|
||||
$(EXIT_ON_ERROR) \
|
||||
for dir in $(ADDONSRC)/*; do \
|
||||
base=`basename $$dir` ; \
|
||||
(cd $$dir && zip $(TESTXPI)/$$base.xpi *) \
|
||||
done \
|
||||
fi
|
||||
|
||||
|
9
mobile/chrome/tests/addons/browser_install1_1/bootstrap.js
vendored
Normal file
9
mobile/chrome/tests/addons/browser_install1_1/bootstrap.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
function install(data, reason) {}
|
||||
function startup(data, reason) {}
|
||||
function shutdown(data, reason) {}
|
||||
function uninstall(data, reason) {}
|
||||
|
24
mobile/chrome/tests/addons/browser_install1_1/install.rdf
Normal file
24
mobile/chrome/tests/addons/browser_install1_1/install.rdf
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>addon1@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:updateURL>http://example.com/browser/mobile/chrome/browser_upgrade.rdf</em:updateURL>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Install Tests</em:name>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
22
mobile/chrome/tests/addons/browser_install1_2/install.rdf
Normal file
22
mobile/chrome/tests/addons/browser_install1_2/install.rdf
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>addon2@tests.mozilla.org</em:id>
|
||||
<em:version>2.0</em:version>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Install Tests</em:name>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
23
mobile/chrome/tests/addons/browser_install1_3/install.rdf
Normal file
23
mobile/chrome/tests/addons/browser_install1_3/install.rdf
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>addon1@tests.mozilla.org</em:id>
|
||||
<em:version>3.0</em:version>
|
||||
<em:updateURL>http://example.com/browser/mobile/chrome/browser_upgrade.rdf</em:updateURL>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Install Tests</em:name>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
315
mobile/chrome/tests/browser_addons.js
Normal file
315
mobile/chrome/tests/browser_addons.js
Normal file
@ -0,0 +1,315 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
Components.utils.import("resource://gre/modules/AddonUpdateChecker.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const RELATIVE_DIR = "browser/mobile/chrome/";
|
||||
const TESTROOT = "http://example.com/" + RELATIVE_DIR;
|
||||
const TESTROOT2 = "http://example.org/" + RELATIVE_DIR;
|
||||
const PREF_LOGGING_ENABLED = "extensions.logging.enabled";
|
||||
const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults";
|
||||
const CHROME_NAME = "mochikit";
|
||||
const PREF_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"
|
||||
const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
|
||||
const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
|
||||
const PREF_GETADDONS_GETRECOMMENDED = "extensions.getAddons.recommended.url";
|
||||
const PREF_GETADDONS_BROWSERECOMMENDED = "extensions.getAddons.recommended.browseURL";
|
||||
const SEARCH_URL = TESTROOT + "browser_details.xml";
|
||||
|
||||
var addons = [{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name : "Install Tests",
|
||||
iconURL: "http://example.com/icon.png",
|
||||
homepageURL: "http://example.com/",
|
||||
version: "1.0",
|
||||
description: "Test add-on",
|
||||
sourceURL: TESTROOT + "addons/browser_install1_1.xpi"
|
||||
},
|
||||
{
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name : "Install Tests 2",
|
||||
iconURL: "http://example.com/icon.png",
|
||||
homepageURL: "http://example.com/",
|
||||
version: "1.0",
|
||||
description: "Test add-on 2",
|
||||
sourceURL: TESTROOT + "addons/browser_install1_2.xpi"
|
||||
}];
|
||||
|
||||
|
||||
var gPendingTests = [];
|
||||
var gTestsRun = 0;
|
||||
var gTestStart = null;
|
||||
var gDate = new Date(2010, 7, 1);
|
||||
var gApp = document.getElementById("bundle_brand").getString("brandShortName");
|
||||
var gCategoryUtilities;
|
||||
var gSearchCount = 0;
|
||||
var gProvider = null;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
Services.prefs.setCharPref(PREF_GETADDONS_GETRECOMMENDED, TESTROOT + "browser_install.xml");
|
||||
Services.prefs.setCharPref(PREF_GETADDONS_BROWSERECOMMENDED, TESTROOT + "browser_install.xml");
|
||||
Services.prefs.setCharPref(PREF_GETADDONS_BROWSESEARCHRESULTS, TESTROOT + "browser_install.xml");
|
||||
Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, TESTROOT + "browser_install.xml");
|
||||
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function end_test() {
|
||||
close_manager(function() {
|
||||
Services.prefs.clearUserPref(PREF_GETADDONS_GETRECOMMENDED);
|
||||
Services.prefs.clearUserPref(PREF_GETADDONS_BROWSERECOMMENDED);
|
||||
Services.prefs.clearUserPref(PREF_GETADDONS_GETSEARCHRESULTS);
|
||||
Services.prefs.clearUserPref(PREF_GETADDONS_BROWSESEARCHRESULTS);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function add_test(test) {
|
||||
gPendingTests.push(test);
|
||||
}
|
||||
|
||||
function run_next_test() {
|
||||
if (gTestsRun > 0)
|
||||
info("Test " + gTestsRun + " took " + (Date.now() - gTestStart) + "ms");
|
||||
|
||||
if (gPendingTests.length == 0) {
|
||||
end_test();
|
||||
return;
|
||||
}
|
||||
|
||||
gTestsRun++;
|
||||
var test = gPendingTests.shift();
|
||||
if (test.name)
|
||||
info("Running test " + gTestsRun + " (" + test.name + ")");
|
||||
else
|
||||
info("Running test " + gTestsRun);
|
||||
|
||||
gTestStart = Date.now();
|
||||
test();
|
||||
}
|
||||
|
||||
function checkAttribute(aElt, aAttr, aVal) {
|
||||
ok(aElt.hasAttribute(aAttr), "Element has " + aAttr + " attribute");
|
||||
if(aVal)
|
||||
is(aElt.getAttribute(aAttr), aVal, "Element has " + aAttr + " attribute with value " + aVal);
|
||||
}
|
||||
|
||||
function installExtension(elt, aListener) {
|
||||
elt.parentNode.ensureElementIsVisible(elt);
|
||||
elt.install.addListener(aListener)
|
||||
|
||||
var button = document.getAnonymousElementByAttribute(elt, "class", "addon-install hide-on-install hide-on-restart");
|
||||
ok(!!button, "Extension has install button");
|
||||
ExtensionsView.installFromRepo(elt);
|
||||
}
|
||||
|
||||
function isRestartShown(aShown, isUpdate) {
|
||||
let msg = document.getElementById("addons-messages");
|
||||
ok(!!msg, "Have message box");
|
||||
let notification = msg.getNotificationWithValue("restart-app");
|
||||
is(!!notification, aShown, "Restart exists = " + aShown);
|
||||
|
||||
if(notification) {
|
||||
let label = "";
|
||||
dump("Label: " + notification.label + "\n");
|
||||
if(isUpdate)
|
||||
label = "Add-ons updated. Restart to complete changes."
|
||||
else
|
||||
label = "Restart to complete changes.";
|
||||
is(notification.label, label, "Restart shows correct message");
|
||||
}
|
||||
msg.removeAllNotifications(true)
|
||||
}
|
||||
|
||||
function checkAddonListing(aAddon, elt) {
|
||||
ok(!!elt, "Element exists for addon");
|
||||
checkAttribute(elt, "id", "urn:mozilla:item:" + aAddon.id);
|
||||
checkAttribute(elt, "addonID", aAddon.id);
|
||||
checkAttribute(elt, "typeName", "search");
|
||||
checkAttribute(elt, "name", aAddon.name);
|
||||
checkAttribute(elt, "version", aAddon.version);
|
||||
checkAttribute(elt, "iconURL", aAddon.iconURL);
|
||||
checkAttribute(elt, "description", aAddon.description)
|
||||
checkAttribute(elt, "homepageURL", aAddon.homepageURL);
|
||||
checkAttribute(elt, "sourceURL", aAddon.sourceURL);
|
||||
ok(elt.install, "Extension has install property");
|
||||
}
|
||||
function checkUpdate(aAddon, aSettings) {
|
||||
let os = Services.obs;
|
||||
let ul = new updateListener(aSettings);
|
||||
os.addObserver(ul, "addon-update-ended", false);
|
||||
|
||||
ExtensionsView.updateAll();
|
||||
//aAddon.findUpdates(new updateListener(aSettings), AddonManager.UPDATE_WHEN_USER_REQUESTED, "4.0", "4.0");
|
||||
}
|
||||
|
||||
function get_addon_element(aId) {
|
||||
|
||||
var node = document.getElementById("addons-list").firstChild;
|
||||
while (node) {
|
||||
if (("urn:mozilla:item:" + aId) == node.id)
|
||||
return node;
|
||||
node = node.nextSibling;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
function open_manager(aView, aCallback) {
|
||||
var panelButton = document.getElementById("tool-panel-open")
|
||||
panelButton.click();
|
||||
var addonsButton = document.getElementById("tool-addons");
|
||||
addonsButton.click();
|
||||
|
||||
ExtensionsView.init();
|
||||
ExtensionsView._delayedInit();
|
||||
|
||||
// XXX - give the list time to add addons from the repo
|
||||
// find a better way to do this
|
||||
setTimeout(function() {
|
||||
aCallback();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function close_manager(aCallback) {
|
||||
var prefsButton = document.getElementById("tool-preferences");
|
||||
prefsButton.click();
|
||||
|
||||
BrowserUI.hidePanel();
|
||||
aCallback();
|
||||
}
|
||||
// Installs a bootstrapped (restartless) addon first, and then
|
||||
// updates it to a non-bootstrapped addon. Checks to make sure
|
||||
// restart notifications are shown at the right time
|
||||
|
||||
// We currently don't handle bootstrapped addons very well, i.e.
|
||||
// they aren't moved from the browse area into the main area
|
||||
add_test(function() {
|
||||
open_manager(null, function() {
|
||||
var elt = get_addon_element("addon1@tests.mozilla.org");
|
||||
checkAddonListing(addons[0], elt);
|
||||
installExtension(elt, new installListener({
|
||||
showRestart: false,
|
||||
willFail: false,
|
||||
onComplete: function(aAddon) {
|
||||
checkUpdate(aAddon, {
|
||||
showRestart: true,
|
||||
willFail: false,
|
||||
addon: addons[0],
|
||||
onComplete: function(aAddon) {
|
||||
close_manager(run_next_test);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Installs a non-bootstrapped addon and checks to make sure
|
||||
// the correct restart notifications are shown
|
||||
add_test(function() {
|
||||
open_manager(null, function() {
|
||||
var elt = get_addon_element("addon2@tests.mozilla.org");
|
||||
checkAddonListing(addons[1], elt);
|
||||
installExtension(elt, new installListener({
|
||||
showRestart: true,
|
||||
willFail: false,
|
||||
onComplete: run_next_test,
|
||||
}));
|
||||
});
|
||||
})
|
||||
|
||||
function installListener(aSettings) {
|
||||
this.willFail = aSettings.willFail;
|
||||
this.onComplete = aSettings.onComplete;
|
||||
this.showRestart = aSettings.showRestart;
|
||||
}
|
||||
|
||||
installListener.prototype = {
|
||||
|
||||
onNewInstall : function(install) { },
|
||||
onDownloadStarted : function(install) {
|
||||
info("download started");
|
||||
},
|
||||
onDownloadProgress : function(install) {
|
||||
info("download progress");
|
||||
},
|
||||
onDownloadEnded : function(install) {
|
||||
info("download ended");
|
||||
},
|
||||
onDownloadCancelled : function(install) {
|
||||
info("download cancelled");
|
||||
},
|
||||
onDownloadFailed : function(install) {
|
||||
if(this.willFail)
|
||||
ok(false, "Install failed");
|
||||
info("download failed");
|
||||
},
|
||||
onInstallStarted : function(install) {
|
||||
info("Install started");
|
||||
},
|
||||
onInstallEnded : function(install, addon) {
|
||||
// this needs to fire after the extension manager's install ended
|
||||
let self = this;
|
||||
setTimeout(function() {
|
||||
info("Install ended");
|
||||
isRestartShown(self.showRestart, false);
|
||||
if(self.onComplete)
|
||||
self.onComplete(addon);
|
||||
}, 0);
|
||||
},
|
||||
onInstallCancelled : function(install) {
|
||||
info("Install cancelled");
|
||||
},
|
||||
onInstallFailed : function(install) {
|
||||
if(this.willFail)
|
||||
ok(false, "Install failed");
|
||||
info("install failed");
|
||||
},
|
||||
onExternalInstall : function(install, existing, needsRestart) { },
|
||||
};
|
||||
|
||||
function updateListener(aSettings) {
|
||||
this.willFail = aSettings.willFail;
|
||||
this.onComplete = aSettings.onComplete;
|
||||
this.showRestart = aSettings.showRestart;
|
||||
this.addon = aSettings.addon;
|
||||
}
|
||||
|
||||
updateListener.prototype = {
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
switch(aTopic) {
|
||||
case "addon-update-ended" :
|
||||
info("Update ended");
|
||||
// this needs to fire after the extension manager's install ended
|
||||
let self = this;
|
||||
|
||||
let json = aSubject.QueryInterface(Ci.nsISupportsString).data;
|
||||
let update = JSON.parse(json);
|
||||
if(update.id == this.addon.id) {
|
||||
let element = get_addon_element(update.id);
|
||||
ok(!!element, "Have element for upgrade");
|
||||
|
||||
let addon = element.addon;
|
||||
|
||||
setTimeout(function() {
|
||||
isRestartShown(self.showRestart, true);
|
||||
if(self.onComplete)
|
||||
self.onComplete(addon);
|
||||
}, 100);
|
||||
let os = Services.obs;
|
||||
os.removeObserver(this, "addon-update-ended", false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
58
mobile/chrome/tests/browser_install.xml
Normal file
58
mobile/chrome/tests/browser_install.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<searchresults total_results="2">
|
||||
<addon>
|
||||
<name>Install Tests</name>
|
||||
<type id='1'>Extension</type>
|
||||
<guid>addon1@tests.mozilla.org</guid>
|
||||
<version>1.0</version>
|
||||
<icon>http://example.com/icon.png</icon>
|
||||
<homepage>http://example.com/</homepage>
|
||||
<authors>
|
||||
<author>
|
||||
<name>Test Creator</name>
|
||||
<link>http://example.com/creator.html</link>
|
||||
</author>
|
||||
</authors>
|
||||
<status id='4'>Public</status>
|
||||
<summary>Test add-on</summary>
|
||||
<description>Test add-on</description>
|
||||
<compatible_applications>
|
||||
<application>
|
||||
<name>Fennec</name>
|
||||
<appID>{a23983c0-fd0e-11dc-95ff-0800200c9a66}</appID>
|
||||
<min_version>0</min_version>
|
||||
<max_version>5</max_version>
|
||||
</application>
|
||||
</compatible_applications>
|
||||
<compatible_os>ALL</compatible_os>
|
||||
<install size="2">http://example.com/browser/mobile/chrome/addons/browser_install1_1.xpi</install>
|
||||
</addon>
|
||||
|
||||
<addon>
|
||||
<name>Install Tests 2</name>
|
||||
<type id='1'>Extension</type>
|
||||
<guid>addon2@tests.mozilla.org</guid>
|
||||
<version>1.0</version>
|
||||
<icon>http://example.com/icon.png</icon>
|
||||
<homepage>http://example.com/</homepage>
|
||||
<authors>
|
||||
<author>
|
||||
<name>Test Creator</name>
|
||||
<link>http://example.com/creator.html</link>
|
||||
</author>
|
||||
</authors>
|
||||
<status id='4'>Public</status>
|
||||
<summary>Test add-on 2</summary>
|
||||
<description>Test add-on 2</description>
|
||||
<compatible_applications>
|
||||
<application>
|
||||
<name>Fennec</name>
|
||||
<appID>{a23983c0-fd0e-11dc-95ff-0800200c9a66}</appID>
|
||||
<min_version>0</min_version>
|
||||
<max_version>5</max_version>
|
||||
</application>
|
||||
</compatible_applications>
|
||||
<compatible_os>ALL</compatible_os>
|
||||
<install size="2">http://example.com/browser/mobile/chrome/addons/browser_install1_2.xpi</install>
|
||||
</addon>
|
||||
</searchresults>
|
27
mobile/chrome/tests/browser_upgrade.rdf
Normal file
27
mobile/chrome/tests/browser_upgrade.rdf
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:extension:addon1@tests.mozilla.org">
|
||||
<em:updates>
|
||||
<Seq>
|
||||
<li>
|
||||
<Description>
|
||||
<em:version>2.0</em:version>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
<em:updateLink>http://example.com/browser/mobile/chrome/addons/browser_install1_3.xpi</em:updateLink>
|
||||
<em:updateHash>sha1:8c4d2f5c9eadc8850558a9a9618aae25886dbe7c</em:updateHash>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</li>
|
||||
</Seq>
|
||||
</em:updates>
|
||||
</Description>
|
||||
|
||||
</RDF>
|
Loading…
Reference in New Issue
Block a user