[growl integration] new version of the Growl popup message handler

cusax-fix
Romain Kuntz 17 years ago
parent 4d40c63dac
commit 0512596b03

@ -6,7 +6,10 @@
*/
package net.java.sip.communicator.impl.growlnotification;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.service.systray.*;
import org.osgi.framework.*;
import net.java.sip.communicator.util.*;
@ -15,6 +18,7 @@
* Activates the GrowlNotificationService
*
* @author Romain Kuntz
* @author Egidijus Jankauskas
*/
public class GrowlNotificationActivator
implements BundleActivator
@ -27,11 +31,21 @@ public class GrowlNotificationActivator
private static final Logger logger =
Logger.getLogger(GrowlNotificationActivator.class);
/**
* A reference to the configuration service.
*/
private static ConfigurationService configService;
/**
* A reference to the resource management service.
*/
private static ResourceManagementService resourcesService;
/**
* A reference to the Growl notification service
*/
private static GrowlNotificationServiceImpl handler;
/**
* Initialize and start Growl Notifications Service
*
@ -40,32 +54,51 @@ public class GrowlNotificationActivator
*/
public void start(BundleContext bc) throws Exception
{
/* Check Java version: do not start if Java 6 */
/* Actually, this plugin uses the Growl Java bindings which
* in turn uses the Cocoa Java bridge. Java 6 on Mac OS X is
* 64-bit only (as of 01/2008), and the Cocoa-Java bridge
* will certainly never get any 64-bit support (it has been
* deprecated).
*/
String version = System.getProperty("java.version");
char minor = version.charAt(2);
if(minor > '5') {
logger.info("Growl Notification Plugin cannot be started " +
"on JDK version " + version);
} else {
bundleContext = bc;
/* Create and start the Growl Notification service. */
new GrowlNotificationServiceImpl().start(bc);
logger.info("Growl Notification ...[Starting]");
bundleContext = bc;
getConfigurationService();
logger.info("Growl Notification Plugin ...[Started]");
handler = new GrowlNotificationServiceImpl();
if (handler.isGrowlInstalled())
{
handler.start(bc);
bc.registerService(PopupMessageHandler.class.getName(), handler, null);
} else
{
logger.info("Growl Notification ...[Aborted]");
return;
}
logger.info("Growl Notification ...[Started]");
}
public void stop(BundleContext bContext) throws Exception
{
handler.stop(bContext);
logger.info("Growl Notification Service ...[Stopped]");
}
/**
* Returns the <tt>ConfigurationService</tt> obtained from the bundle
* context.
* @return the <tt>ConfigurationService</tt> obtained from the bundle
* context
*/
public static ConfigurationService getConfigurationService()
{
if(configService == null) {
ServiceReference configReference = bundleContext
.getServiceReference(ConfigurationService.class.getName());
configService = (ConfigurationService) bundleContext
.getService(configReference);
}
return configService;
}
/**
* Returns the <tt>ResourceManagementService</tt> obtained from the bundle
* context.
@ -78,6 +111,5 @@ public static ResourceManagementService getResources()
resourcesService =
ResourceManagementServiceUtils.getService(bundleContext);
return resourcesService;
}
}
}

@ -6,182 +6,104 @@
*/
package net.java.sip.communicator.impl.growlnotification;
import java.lang.reflect.*;
import java.util.*;
import org.osgi.framework.*;
import com.growl.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
import net.java.sip.communicator.util.*;
import org.growl4j.*;
// TO-DO: use a better icon in registration.
/**
* The Growl Notification Service displays on-screen information such as
* messages or call received, etc.
*
* @author Romain Kuntz
* @author Egidijus Jankauskas
*/
public class GrowlNotificationServiceImpl
implements PopupMessageHandler
implements PopupMessageHandler,
GrowlCallbacksListener
{
/**
* The logger for this class.
*/
private static Logger logger =
Logger.getLogger(GrowlNotificationServiceImpl.class);
/**
* The Growl notifier
* A variable that acts as a buffer to temporarily keep all PopupMessages
* that were sent to Growl Daemon.
*/
private Growl notifier;
private static final HashMap<Long, PopupMessage> shownPopups =
new HashMap<Long, PopupMessage>(10);
private Growl growl = null;
/**
* The notifyGrowlOf/setAllowedNotifications/setDefaultNotifications
* methods of the growl class. We use reflection to access them
* in order to avoid compilation errors on non mac platforms.
*/
private Method notifyMethod = null;
private Method setAllowedNotifMethod = null;
private Method setDefaultNotifMethod = null;
/* All Growl Notifications and the default ones */
private String [] allNotif =
new String[] { "SIP Communicator Started",
"Protocol events",
"Message Received",
"Message Sent"};
private String [] defaultNotif =
new String[] { "SIP Communicator Started",
"Message Received" };
/**
* The path to the SIP Communicator icon used in Growl's configuration
* menu and protocol events messages
*/
private String sipIconPath = "resources/images/logo/sc_logo_128x128.icns";
/** The list of all added popup listeners */
private final List<SystrayPopupMessageListener> popupMessageListeners =
new Vector<SystrayPopupMessageListener>();
/**
* starts the service. Creates a Growl notifier, and check the current
* registerd protocol providers which supports BasicIM and adds message
* Starts the service. Creates a Growl notifier, and check the current
* registered protocol providers which supports BasicIM and adds message
* listener to them.
*
* @param bc a currently valid bundle context
* @throws java.lang.Exception if we fail initializing the growl notifier.
*/
public void start(BundleContext bc)
throws Exception
{
logger.debug("Starting the Growl Notification implementation.");
/* Register to Growl */
try
{
Constructor<Growl> constructor = Growl.class.getConstructor(
new Class[] { String.class, String.class });
notifier = constructor.newInstance(
new Object[]{"SIP Communicator", sipIconPath});
//init the setAllowedNotifications method
setAllowedNotifMethod = Growl.class.getMethod(
"setAllowedNotifications"
, new Class[]{String[].class});
//init the setDefaultNotifications method
setDefaultNotifMethod = Growl.class.getMethod(
"setDefaultNotifications"
, new Class[]{String[].class});
//init the notifyGrowlOf method
notifyMethod = Growl.class.getMethod(
"notifyGrowlOf"
, new Class[]{String.class, String.class,
String.class, String.class});
setAllowedNotifications(allNotif);
setDefaultNotifications(defaultNotif);
notifier.register();
notifyGrowlOf("SIP Communicator Started"
, sipIconPath
, "Welcome to SIP Communicator"
, "http://www.sip-communicator.org");
}
catch (Exception ex)
if(Growl.isGrowlRunning())
{
logger.error("Could not send the message to Growl", ex);
throw ex;
}
bc.registerService(PopupMessageHandler.class.getName(), this, null);
String[] dict = { "Default", "Welcome message" };
byte[] sipIcon = GrowlNotificationActivator.getResources().
getImageInBytes("service.gui.SIP_COMMUNICATOR_LOGO_45x45");
growl = new Growl ("SIP Communicator", "net.sip-communicator", sipIcon, dict, dict);
growl.addClickedNotificationsListener(this);
growl.notifyGrowlOf("SIP Communicator",
"http://www.sip-communicator.org/",
"Welcome message",
null, null);
}
}
/**
* stops the service.
* Stops the service.
*
* @param bc BundleContext
*/
public void stop(BundleContext bc)
{
}
/**
* Convenience method that defers to notifier.notifyGrowlOf() using
* reflection without referencing it directly. The purpose of this method
* is to allow the class to compile on non-mac systems.
*
* @param inNotificationName The name of one of the notifications we told
* growl about.
* @param inTitle The Title of our Notification as Growl will show it
* @param inDescription The Description of our Notification as Growl will
* display it
*
* @throws Exception When a notification is not known
*/
public void notifyGrowlOf(String inNotificationName,
String inImagePath,
String inTitle,
String inDescription)
throws Exception
{
// remove eventual html code before showing the popup message
inDescription = inDescription.replaceAll("</?\\w++[^>]*+>", "");
notifyMethod.invoke(
notifier, new Object[]{inNotificationName, inImagePath,
inTitle, inDescription});
if (growl != null)
{
growl.doFinalCleanUp();
}
}
/**
* Convenience method that defers to notifier.setAllowedNotifications()
* using reflection without referencing it directly. The purpose of this
* method is to allow the class to compile on non-mac systems.
*
* @param inAllNotes The list of allowed Notifications
* Checks if Growl is present on the system
* @return <code>true</code> if Growl is installed and <code>false</code> otherwise
*/
public void setAllowedNotifications(String [] inAllNotes)
throws Exception
public boolean isGrowlInstalled()
{
setAllowedNotifMethod.invoke(notifier, new Object[]{inAllNotes});
return Growl.isGrowlInstalled();
}
/**
* Convenience method that defers to notifier.setDefaultNotifications()
* using reflection without referencing it directly. The purpose of this
* method is to allow the class to compile on non-mac systems.
*
* @param inDefNotes The list of default Notifications
* Checks if Growl is running
* @return <code>true</code> if Growl is running and <code>false</code> otherwise
*/
public void setDefaultNotifications(String [] inDefNotes)
throws Exception
public boolean isGrowlRunning()
{
setDefaultNotifMethod.invoke(notifier, new Object[]{inDefNotes});
return Growl.isGrowlRunning();
}
public void addPopupMessageListener(SystrayPopupMessageListener listener)
@ -208,19 +130,82 @@ public void removePopupMessageListener(SystrayPopupMessageListener listener)
*/
public void showPopupMessage(PopupMessage popupMessage)
{
try
{
notifyGrowlOf("Message Received"
, sipIconPath
, popupMessage.getMessageTitle()
, popupMessage.getMessage());
long timestamp = System.currentTimeMillis();
synchronized(shownPopups) {
shownPopups.put(timestamp, popupMessage);
}
catch (Exception ex)
String messageBody = popupMessage.getMessage();
String messageTitle = popupMessage.getMessageTitle();
// remove eventual HTML code before showing the pop-up message
messageBody = messageBody.replaceAll("</?\\w++[^>]*+>", "");
messageTitle = messageTitle.replaceAll("</?\\w++[^>]*+>", "");
growl.notifyGrowlOf(messageTitle,
messageBody,
"Default",
popupMessage.getIcon(),
timestamp);
}
/**
* Notifies all interested listeners that a <tt>SystrayPopupMessageEvent</tt>
* occured.
*
* @param SystrayPopupMessageEvent the evt to send to listener.
*/
private void firePopupMessageClicked(SystrayPopupMessageEvent evt)
{
logger.trace("Will dispatch the following popup event: " + evt);
List<SystrayPopupMessageListener> listeners;
synchronized (popupMessageListeners)
{
logger.error("Could not notify the received message to Growl", ex);
listeners =
new ArrayList<SystrayPopupMessageListener>(
popupMessageListeners);
}
for (SystrayPopupMessageListener listener : listeners)
listener.popupMessageClicked(evt);
}
/**
* This method is called by Growl when the Growl notification is not clicked
* @param context is an object that is used to identify sent notification
*/
public void growlNotificationTimedOut(Object context)
{
PopupMessage m = (PopupMessage)shownPopups.get(context);
if (m != null) {
synchronized(shownPopups) {
shownPopups.remove(context);
}
logger.trace("Growl notification timed-out :" +
m.getMessageTitle() + ": " + m.getMessage());
}
}
/**
* This method is called by Growl when the Growl notification is clicked
* @param context is an object that is used to identify sent notification
*/
public void growlNotificationWasClicked(Object context)
{
PopupMessage m = (PopupMessage)shownPopups.get(context);
if (m != null) {
synchronized(shownPopups) {
shownPopups.remove(context);
}
firePopupMessageClicked(new SystrayPopupMessageEvent(this, m.getTag()));
logger.trace("Growl message clicked :" +
m.getMessageTitle() + ": " + m.getMessage());
}
}
/**
* Implements <tt>toString</tt> from <tt>PopupMessageHandler</tt>
* @return a description of this handler
@ -230,4 +215,15 @@ public String toString()
return GrowlNotificationActivator.getResources()
.getI18NString("impl.growlnotification.POPUP_MESSAGE_HANDLER");
}
/**
* Implements <tt>getPreferenceIndex</tt> from <tt>PopupMessageHandler</tt>.
* This handler is able to show images, detect clicks, match a click to a
* message, and use a native popup mechanism, thus the index is 4.
* @return a preference index
*/
public int getPreferenceIndex()
{
return 4;
}
}

@ -5,8 +5,11 @@ Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.util,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.systray,
net.java.sip.communicator.service.systray.event,
com.growl
net.java.sip.communicator.util.swing,
org.growl4j

Loading…
Cancel
Save