mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 905262 - Create a JS add-on API for adding content to the promotional banner. r=wesj
This commit is contained in:
parent
eebb5ab023
commit
93f401fd87
@ -2257,7 +2257,7 @@ public class GeckoAppShell
|
||||
sEventDispatcher.registerEventListener(event, listener);
|
||||
}
|
||||
|
||||
static EventDispatcher getEventDispatcher() {
|
||||
public static EventDispatcher getEventDispatcher() {
|
||||
return sEventDispatcher;
|
||||
}
|
||||
|
||||
|
@ -5,16 +5,31 @@
|
||||
|
||||
package org.mozilla.gecko.home;
|
||||
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class HomeBanner extends LinearLayout {
|
||||
public class HomeBanner extends LinearLayout
|
||||
implements GeckoEventListener {
|
||||
private static final String LOGTAG = "GeckoHomeBanner";
|
||||
|
||||
public HomeBanner(Context context) {
|
||||
this(context, null);
|
||||
@ -43,9 +58,78 @@ public class HomeBanner extends LinearLayout {
|
||||
HomeBanner.this.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Send the current message id back to JS.
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("HomeBanner:Click", (String) getTag()));
|
||||
}
|
||||
});
|
||||
|
||||
GeckoAppShell.getEventDispatcher().registerEventListener("HomeBanner:Data", this);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("HomeBanner:Get", null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
GeckoAppShell.getEventDispatcher().unregisterEventListener("HomeBanner:Data", this);
|
||||
}
|
||||
|
||||
public boolean isDismissed() {
|
||||
return (getVisibility() == View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
try {
|
||||
// Store the current message id to pass back to JS in the view's OnClickListener.
|
||||
setTag(message.getString("id"));
|
||||
|
||||
final String text = message.getString("text");
|
||||
final TextView textView = (TextView) findViewById(R.id.text);
|
||||
|
||||
// Update the banner message on the UI thread.
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
textView.setText(text);
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Exception handling " + event + " message", e);
|
||||
return;
|
||||
}
|
||||
|
||||
final String iconURI = message.optString("iconURI");
|
||||
final ImageView iconView = (ImageView) findViewById(R.id.icon);
|
||||
|
||||
if (TextUtils.isEmpty(iconURI)) {
|
||||
// Hide the image view if we don't have an icon to show.
|
||||
iconView.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
BitmapUtils.getDrawable(getContext(), iconURI, new BitmapUtils.BitmapLoader() {
|
||||
@Override
|
||||
public void onBitmapFound(final Drawable d) {
|
||||
// Bail if getDrawable doesn't find anything.
|
||||
if (d == null) {
|
||||
iconView.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the banner icon on the UI thread.
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
iconView.setImageDrawable(d);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -9,13 +9,13 @@
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:scaleType="centerInside"/>
|
||||
|
||||
<TextView android:id="@+id/text"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:textAppearance="@style/TextAppearance.Widget.HomeBanner"
|
||||
|
132
mobile/android/modules/Home.jsm
Normal file
132
mobile/android/modules/Home.jsm
Normal file
@ -0,0 +1,132 @@
|
||||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Home"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// See bug 915424
|
||||
function resolveGeckoURI(aURI) {
|
||||
if (!aURI)
|
||||
throw "Can't resolve an empty uri";
|
||||
|
||||
if (aURI.startsWith("chrome://")) {
|
||||
let registry = Cc['@mozilla.org/chrome/chrome-registry;1'].getService(Ci["nsIChromeRegistry"]);
|
||||
return registry.convertChromeURL(Services.io.newURI(aURI, null, null)).spec;
|
||||
} else if (aURI.startsWith("resource://")) {
|
||||
let handler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
|
||||
return handler.resolveURI(Services.io.newURI(aURI, null, null));
|
||||
}
|
||||
return aURI;
|
||||
}
|
||||
|
||||
function sendMessageToJava(message) {
|
||||
return Services.androidBridge.handleGeckoMessage(JSON.stringify(message));
|
||||
}
|
||||
|
||||
function BannerMessage(options) {
|
||||
let uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
this.id = uuidgen.generateUUID().toString();
|
||||
|
||||
if ("text" in options && options.text != null)
|
||||
this.text = options.text;
|
||||
|
||||
if ("icon" in options && options.icon != null)
|
||||
this.iconURI = resolveGeckoURI(options.icon);
|
||||
|
||||
if ("onclick" in options && typeof options.onclick === "function")
|
||||
this.onclick = options.onclick;
|
||||
}
|
||||
|
||||
let HomeBanner = {
|
||||
// Holds the messages that will rotate through the banner.
|
||||
_messages: {},
|
||||
|
||||
// A queue used to keep track of which message to show next.
|
||||
_queue: [],
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch(topic) {
|
||||
case "HomeBanner:Get":
|
||||
this._handleGet();
|
||||
break;
|
||||
|
||||
case "HomeBanner:Click":
|
||||
this._handleClick(data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_handleGet: function() {
|
||||
// Get the message from the front of the queue, then add it back
|
||||
// to the end of the queue to show it again later.
|
||||
let id = this._queue.shift();
|
||||
this._queue.push(id);
|
||||
|
||||
let message = this._messages[id];
|
||||
sendMessageToJava({
|
||||
type: "HomeBanner:Data",
|
||||
id: message.id,
|
||||
text: message.text,
|
||||
iconURI: message.iconURI
|
||||
});
|
||||
},
|
||||
|
||||
_handleClick: function(id) {
|
||||
let message = this._messages[id];
|
||||
if (message.onclick)
|
||||
message.onclick();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new banner message to the rotation.
|
||||
*
|
||||
* @return id Unique identifer for the message.
|
||||
*/
|
||||
add: function(options) {
|
||||
let message = new BannerMessage(options);
|
||||
this._messages[message.id] = message;
|
||||
|
||||
// Add the new message to the end of the queue.
|
||||
this._queue.push(message.id);
|
||||
|
||||
// If this is the first message we're adding, add
|
||||
// observers to listen for requests from the Java UI.
|
||||
if (Object.keys(this._messages).length == 1) {
|
||||
Services.obs.addObserver(this, "HomeBanner:Get", false);
|
||||
Services.obs.addObserver(this, "HomeBanner:Click", false);
|
||||
}
|
||||
|
||||
return message.id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a banner message from the rotation.
|
||||
*
|
||||
* @param id The id of the message to remove.
|
||||
*/
|
||||
remove: function(id) {
|
||||
delete this._messages[id];
|
||||
|
||||
// Remove the message from the queue.
|
||||
let index = this._queue.indexOf(id);
|
||||
this._queue.splice(index, 1);
|
||||
|
||||
// If there are no more messages, remove the observers.
|
||||
if (Object.keys(this._messages).length == 0) {
|
||||
Services.obs.removeObserver(this, "HomeBanner:Get");
|
||||
Services.obs.removeObserver(this, "HomeBanner:Click");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Public API
|
||||
this.Home = {
|
||||
banner: HomeBanner
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'ContactService.jsm',
|
||||
'Home.jsm',
|
||||
'JNI.jsm',
|
||||
'LightweightThemeConsumer.jsm',
|
||||
'OrderedBroadcast.jsm',
|
||||
|
Loading…
Reference in New Issue
Block a user