Bug 958192 - Use gecko messages to request current set of available panels from JS. r=lucasr

This commit is contained in:
Margaret Leibovic 2014-01-14 15:08:10 -08:00
parent 2dae43534f
commit 80b44e380a
3 changed files with 102 additions and 65 deletions

View File

@ -6,7 +6,9 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONArray;
import org.json.JSONException;
@ -19,7 +21,11 @@ import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class PanelManager implements GeckoEventListener {
private static final String LOGTAG = "GeckoPanelManager";
@ -34,54 +40,73 @@ public class PanelManager implements GeckoEventListener {
}
}
private final Context mContext;
public PanelManager(Context context) {
mContext = context;
// Add a listener to handle any new panels that are added after the panels have been loaded.
GeckoAppShell.getEventDispatcher().registerEventListener("HomePanels:Added", this);
public interface RequestCallback {
public void onComplete(List<PanelInfo> panelInfos);
}
private static AtomicInteger sRequestId = new AtomicInteger(0);
// Stores set of pending request callbacks.
private static final Map<Integer, RequestCallback> sCallbacks = Collections.synchronizedMap(new HashMap<Integer, RequestCallback>());
/**
* Reads list info from SharedPreferences. Don't call this on the main thread!
* Asynchronously fetches list of available panels from Gecko.
*
* @return List<PanelInfo> A list of PanelInfos for each registered list.
* @param callback onComplete will be called on the UI thread.
*/
public List<PanelInfo> getPanelInfos() {
final ArrayList<PanelInfo> panelInfos = new ArrayList<PanelInfo>();
public void requestAvailablePanels(RequestCallback callback) {
final int requestId = sRequestId.getAndIncrement();
// XXX: We need to use PreferenceManager right now because that's what SharedPreferences.jsm uses (see bug 940575)
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
final String prefValue = prefs.getString("home_lists", "");
if (!TextUtils.isEmpty(prefValue)) {
try {
final JSONArray lists = new JSONArray(prefValue);
for (int i = 0; i < lists.length(); i++) {
final JSONObject list = lists.getJSONObject(i);
final PanelInfo info = new PanelInfo(list.getString("id"), list.getString("title"));
panelInfos.add(info);
}
} catch (JSONException e) {
Log.e(LOGTAG, "Exception getting list info", e);
synchronized(sCallbacks) {
// If there are no pending callbacks, register the event listener.
if (sCallbacks.isEmpty()) {
GeckoAppShell.getEventDispatcher().registerEventListener("HomePanels:Data", this);
}
sCallbacks.put(requestId, callback);
}
return panelInfos;
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("HomePanels:Get", Integer.toString(requestId)));
}
/**
* Listens for "HomePanels:Added"
* Handles "HomePanels:Data" events.
*/
@Override
public void handleMessage(String event, JSONObject message) {
final ArrayList<PanelInfo> panelInfos = new ArrayList<PanelInfo>();
try {
final PanelInfo info = new PanelInfo(message.getString("id"), message.getString("title"));
final JSONArray panels = message.getJSONArray("panels");
final int count = panels.length();
for (int i = 0; i < count; i++) {
final PanelInfo panelInfo = getPanelInfoFromJSON(panels.getJSONObject(i));
panelInfos.add(panelInfo);
}
// Do something to update the set of list pages.
final RequestCallback callback;
final int requestId = message.getInt("requestId");
synchronized(sCallbacks) {
callback = sCallbacks.remove(requestId);
// Unregister the event listener if there are no more pending callbacks.
if (sCallbacks.isEmpty()) {
GeckoAppShell.getEventDispatcher().unregisterEventListener("HomePanels:Data", this);
}
}
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
callback.onComplete(panelInfos);
}
});
} catch (JSONException e) {
Log.e(LOGTAG, "Exception handling " + event + " message", e);
}
}
private PanelInfo getPanelInfoFromJSON(JSONObject jsonPanelInfo) throws JSONException {
return new PanelInfo(jsonPanelInfo.getString("id"), jsonPanelInfo.getString("title"));
}
}

View File

@ -134,6 +134,22 @@ var LazyNotificationGetter = {
});
});
// Lazily-loaded JS modules that use observer notifications
[
["Home", ["HomePanels:Get"], "resource://gre/modules/Home.jsm"],
].forEach(module => {
let [name, notifications, resource] = module;
XPCOMUtils.defineLazyModuleGetter(this, name, resource);
notifications.forEach(notification => {
let o = {
notification: notification,
observe: (s, t, d) => this[name].observe(s, t, d)
};
Services.obs.addObserver(o, notification, false);
LazyNotificationGetter.observers.push(o);
});
});
XPCOMUtils.defineLazyServiceGetter(this, "Haptic",
"@mozilla.org/widget/hapticfeedback;1", "nsIHapticFeedback");

View File

@ -145,25 +145,27 @@ function Panel(options) {
this.title = options.title;
}
function HomePanels() {
// XXX: Not renaming this because it is going away in bug 958192
this.PREF_KEY = "home_lists";
let HomePanels = {
// Holds the currrent set of registered panels.
_panels: {},
this._sharedPrefs = new SharedPreferences();
this._panels = {};
_handleGet: function(requestId) {
let panels = [];
for (let id in this._panels) {
let panel = this._panels[id];
panels.push({
id: panel.id,
title: panel.title
});
}
let prefValue = this._sharedPrefs.getCharPref(this.PREF_KEY);
if (!prefValue) {
return;
}
sendMessageToJava({
type: "HomePanels:Data",
panels: panels,
requestId: requestId
});
},
JSON.parse(prefValue).forEach(data => {
let panel = new Panel(data);
this._panels[panel.id] = panel;
});
}
HomePanels.prototype = {
add: function(options) {
let panel = new Panel(options);
if (!panel.id || !panel.title) {
@ -176,35 +178,29 @@ HomePanels.prototype = {
}
this._panels[panel.id] = panel;
this._updateSharedPref();
// Send a message to Java to update the home pager if it's currently showing
sendMessageToJava({
type: "HomePanels:Added",
id: panel.id,
title: panel.title
});
},
remove: function(id) {
delete this._panels[id];
this._updateSharedPref();
},
// Set a shared pref so that Java can know about this panel before Gecko is running
_updateSharedPref: function() {
let panels = [];
for (let id in this._panels) {
let panel = this._panels[id];
panels.push({ id: panel.id, title: panel.title});
}
this._sharedPrefs.setCharPref(this.PREF_KEY, JSON.stringify(panels));
sendMessageToJava({
type: "HomePanels:Remove",
id: panel.id
});
}
};
// Public API
this.Home = {
banner: HomeBanner,
panels: new HomePanels()
panels: HomePanels,
// Lazy notification observer registered in browser.js
observe: function(subject, topic, data) {
switch(topic) {
case "HomePanels:Get":
HomePanels._handleGet(data);
break;
}
}
}