Bug 978991 - Add hooks to let an add-on know when a panel is installed/uninstalled. r=liuche

This commit is contained in:
Margaret Leibovic 2014-04-04 15:55:03 -07:00
parent abe5440530
commit 6082f66aa9
3 changed files with 99 additions and 46 deletions

View File

@ -5,6 +5,8 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.ThreadUtils;
@ -926,6 +928,7 @@ public final class HomeConfig {
private final HomeConfig mHomeConfig;
private final Map<String, PanelConfig> mConfigMap;
private final List<String> mConfigOrder;
private final List<GeckoEvent> mEventQueue;
private final Thread mOriginalThread;
private PanelConfig mDefaultPanel;
@ -939,6 +942,7 @@ public final class HomeConfig {
mOriginalThread = Thread.currentThread();
mConfigMap = new HashMap<String, PanelConfig>();
mConfigOrder = new LinkedList<String>();
mEventQueue = new LinkedList<GeckoEvent>();
mEnabledCount = 0;
mHasChanged = false;
@ -1144,6 +1148,9 @@ public final class HomeConfig {
}
installed = true;
// Add an event to the queue if a new panel is sucessfully installed.
mEventQueue.add(GeckoEvent.createBroadcastEvent("HomePanels:Installed", panelConfig.getId()));
}
mHasChanged = true;
@ -1178,6 +1185,9 @@ public final class HomeConfig {
findNewDefault();
}
// Add an event to the queue if a panel is succesfully uninstalled.
mEventQueue.add(GeckoEvent.createBroadcastEvent("HomePanels:Uninstalled", panelId));
mHasChanged = true;
return true;
}
@ -1246,10 +1256,18 @@ public final class HomeConfig {
final State newConfigState =
new State(mHomeConfig, makeOrderedCopy(true), isDefault());
// Copy the event queue to a new list, so that we only modify mEventQueue on
// the original thread where it was created.
final LinkedList<GeckoEvent> eventQueueCopy = new LinkedList<GeckoEvent>(mEventQueue);
mEventQueue.clear();
ThreadUtils.getBackgroundHandler().post(new Runnable() {
@Override
public void run() {
mHomeConfig.save(newConfigState);
// Send pending events after the new config is saved.
sendEventsToGecko(eventQueueCopy);
}
});
@ -1272,6 +1290,10 @@ public final class HomeConfig {
// need to deep copy the current PanelConfig instances.
mHomeConfig.save(newConfigState);
// Send pending events after the new config is saved.
sendEventsToGecko(mEventQueue);
mEventQueue.clear();
return newConfigState;
}
@ -1289,6 +1311,12 @@ public final class HomeConfig {
return mConfigMap.isEmpty();
}
private void sendEventsToGecko(List<GeckoEvent> events) {
for (GeckoEvent e : events) {
GeckoAppShell.sendEventToGecko(e);
}
}
private class EditorIterator implements Iterator<PanelConfig> {
private final Iterator<String> mOrderIterator;

View File

@ -131,7 +131,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
// Lazily-loaded JS modules that use observer notifications
[
["Home", ["HomePanels:Get", "HomePanels:Authenticate"], "resource://gre/modules/Home.jsm"],
["Home", ["HomePanels:Get", "HomePanels:Authenticate",
"HomePanels:Installed", "HomePanels:Uninstalled"], "resource://gre/modules/Home.jsm"],
].forEach(module => {
let [name, notifications, resource] = module;
XPCOMUtils.defineLazyModuleGetter(this, name, resource);

View File

@ -157,12 +157,74 @@ let HomeBanner = (function () {
});
})();
// We need this function to have access to the HomePanels
// We need this object to have access to the HomePanels
// private members without leaking it outside Home.jsm.
let handlePanelsGet;
let handlePanelsAuthenticate;
let HomePanelsMessageHandlers;
let HomePanels = (function () {
// Functions used to handle messages sent from Java.
HomePanelsMessageHandlers = {
"HomePanels:Get": function handlePanelsGet(data) {
data = JSON.parse(data);
let requestId = data.requestId;
let ids = data.ids || null;
let panels = [];
for (let id in _registeredPanels) {
// Null ids means we want to fetch all available panels
if (ids == null || ids.indexOf(id) >= 0) {
try {
panels.push(_generatePanel(id));
} catch(e) {
Cu.reportError("Home.panels: Invalid options, panel.id = " + id + ": " + e);
}
}
}
sendMessageToJava({
type: "HomePanels:Data",
panels: panels,
requestId: requestId
});
},
"HomePanels:Authenticate": function handlePanelsAuthenticate(id) {
// Generate panel options to get auth handler.
let options = _registeredPanels[id]();
if (!options.authHandler) {
throw "Home.panels: Invalid authHandler for panel.id = " + id;
}
if (!options.authHandler.authenticate || typeof options.authHandler.authenticate !== "function") {
throw "Home.panels: Invalid authHandler authenticate function: panel.id = " + this.id;
}
options.authHandler.authenticate();
},
"HomePanels:Installed": function handlePanelsInstalled(id) {
let options = _registeredPanels[id]();
if (!options.oninstall) {
return;
}
if (typeof options.oninstall !== "function") {
throw "Home.panels: Invalid oninstall function: panel.id = " + this.id;
}
options.oninstall();
},
"HomePanels:Uninstalled": function handlePanelsUninstalled(id) {
let options = _registeredPanels[id]();
if (!options.onuninstall) {
return;
}
if (typeof options.onuninstall !== "function") {
throw "Home.panels: Invalid onuninstall function: panel.id = " + this.id;
}
options.onuninstall();
}
};
// Holds the current set of registered panels that can be
// installed, updated, uninstalled, or unregistered. It maps
// panel ids with the functions that dynamically generate
@ -265,41 +327,6 @@ let HomePanels = (function () {
return new Panel(id, options);
};
handlePanelsGet = function(data) {
let requestId = data.requestId;
let ids = data.ids || null;
let panels = [];
for (let id in _registeredPanels) {
// Null ids means we want to fetch all available panels
if (ids == null || ids.indexOf(id) >= 0) {
try {
panels.push(_generatePanel(id));
} catch(e) {
Cu.reportError("Home.panels: Invalid options, panel.id = " + id + ": " + e);
}
}
}
sendMessageToJava({
type: "HomePanels:Data",
panels: panels,
requestId: requestId
});
};
handlePanelsAuthenticate = function(id) {
// Generate panel options to get auth handler.
let options = _registeredPanels[id]();
if (!options.authHandler) {
throw "Home.panels: Invalid authHandler for panel.id = " + id;
}
if (!options.authHandler.authenticate || typeof options.authHandler.authenticate !== "function") {
throw "Home.panels: Invalid authHandler authenticate function: panel.id = " + this.id;
}
options.authHandler.authenticate();
};
// Helper function used to see if a value is in an object.
let _valueExists = function(obj, value) {
for (let key in obj) {
@ -385,13 +412,10 @@ this.Home = Object.freeze({
// Lazy notification observer registered in browser.js
observe: function(subject, topic, data) {
switch(topic) {
case "HomePanels:Get":
handlePanelsGet(JSON.parse(data));
break;
case "HomePanels:Authenticate":
handlePanelsAuthenticate(data);
break;
if (topic in HomePanelsMessageHandlers) {
HomePanelsMessageHandlers[topic](data);
} else {
Cu.reportError("Home.observe: message handler not found for topic: " + topic);
}
}
});