aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLyubomir Marinov <lyubomir.marinov@jitsi.org>2012-10-18 14:06:40 +0000
committerLyubomir Marinov <lyubomir.marinov@jitsi.org>2012-10-18 14:06:40 +0000
commit98fef59119c22bcb8e09fad6a4a1d787ea84b665 (patch)
tree6e16dff777deaa75755755f7ad449edf51fff836
parent93aeb79acfee9f44297acc7e2e6ca1abb97d19dd (diff)
downloadjitsi-98fef59119c22bcb8e09fad6a4a1d787ea84b665.zip
jitsi-98fef59119c22bcb8e09fad6a4a1d787ea84b665.tar.gz
jitsi-98fef59119c22bcb8e09fad6a4a1d787ea84b665.tar.bz2
Works on preventing sound notifications from playing forever.
-rw-r--r--lib/installer-exclude/libjitsi.jarbin996363 -> 996560 bytes
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java24
-rw-r--r--src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java9
-rw-r--r--src/net/java/sip/communicator/impl/notification/SoundNotificationHandlerImpl.java349
-rw-r--r--src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java45
-rw-r--r--src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java2071
-rw-r--r--src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java1
-rw-r--r--src/net/java/sip/communicator/service/notification/CommandNotificationHandler.java6
-rw-r--r--src/net/java/sip/communicator/service/notification/NotificationData.java115
-rw-r--r--src/net/java/sip/communicator/service/notification/NotificationService.java23
-rw-r--r--src/net/java/sip/communicator/service/notification/NotificationServiceImpl.java1366
-rw-r--r--src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java11
-rw-r--r--src/net/java/sip/communicator/util/dns/ConfigurableDnssecResolver.java7
-rw-r--r--test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java8
14 files changed, 2057 insertions, 1978 deletions
diff --git a/lib/installer-exclude/libjitsi.jar b/lib/installer-exclude/libjitsi.jar
index c1091d4..6feb19a 100644
--- a/lib/installer-exclude/libjitsi.jar
+++ b/lib/installer-exclude/libjitsi.jar
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java b/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
index edf966b..bf8b5b6 100644
--- a/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
+++ b/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
@@ -6,31 +6,23 @@
*/
package net.java.sip.communicator.impl.neomedia;
-import java.awt.*;
-import java.awt.event.*;
import java.beans.*;
import java.util.*;
-import javax.swing.*;
-
import net.java.sip.communicator.impl.neomedia.codec.video.h264.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.service.resources.*;
-import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.impl.neomedia.*;
-import org.jitsi.impl.neomedia.codec.*;
import org.jitsi.impl.neomedia.device.*;
import org.jitsi.service.audionotifier.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.fileaccess.*;
import org.jitsi.service.libjitsi.*;
import org.jitsi.service.neomedia.*;
-import org.jitsi.service.neomedia.codec.*;
import org.jitsi.service.packetlogging.*;
import org.jitsi.service.resources.*;
import org.osgi.framework.*;
@@ -147,11 +139,6 @@ public class NeomediaActivator
deviceConfigurationPropertyChangeListener;
/**
- * Audio configuration dialog.
- */
- private static SIPCommDialog audioConfigDialog = null;
-
- /**
* A {@link MediaConfigurationService} instance.
*/
private static MediaConfigurationImpl mediaConfiguration;
@@ -553,7 +540,7 @@ public class NeomediaActivator
}
/**
- * Fonction called when an audio device is plugged or unplugged.
+ * Function called when an audio device is plugged or unplugged.
*
* @param The property change event which may concern the audio device.
*/
@@ -564,6 +551,7 @@ public class NeomediaActivator
{
NotificationService notificationService
= getNotificationService();
+
if(notificationService != null)
{
// Registers only once to the popup message notification
@@ -573,9 +561,15 @@ public class NeomediaActivator
isRegisteredToPopupMessageListener = true;
managePopupMessageListenerRegistration(true);
}
+
// Fires the popup notification.
ResourceManagementService resources
= NeomediaActivator.getResources();
+ Map<String,Object> extras = new HashMap<String,Object>();
+
+ extras.put(
+ NotificationData.POPUP_MESSAGE_HANDLER_TAG_EXTRA,
+ this);
notificationService.fireNotification(
DEVICE_CONFIGURATION_HAS_CHANGED,
resources.getI18NString(
@@ -585,7 +579,7 @@ public class NeomediaActivator
"impl.media.configform"
+ ".AUDIO_DEVICE_CONFIG_MANAGMENT_CLICK"),
null,
- this);
+ extras);
}
}
}
diff --git a/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java b/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java
index 3395032..c15fb53 100644
--- a/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java
+++ b/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java
@@ -57,11 +57,14 @@ public class PopupMessageNotificationHandlerImpl
return;
if(!StringUtils.isNullOrEmpty(message))
+ {
systray.showPopupMessage(
- new PopupMessage(title, message, icon, tag));
+ new PopupMessage(title, message, icon, tag));
+ }
else
- logger.error("Message is null or empty!",
- new Throwable("Null or empty message"));
+ {
+ logger.error("Message is null or empty!");
+ }
}
/**
diff --git a/src/net/java/sip/communicator/impl/notification/SoundNotificationHandlerImpl.java b/src/net/java/sip/communicator/impl/notification/SoundNotificationHandlerImpl.java
index fad7e2b..c3e4ab2 100644
--- a/src/net/java/sip/communicator/impl/notification/SoundNotificationHandlerImpl.java
+++ b/src/net/java/sip/communicator/impl/notification/SoundNotificationHandlerImpl.java
@@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.notification;
import java.awt.*;
import java.util.*;
+import java.util.concurrent.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.notification.*;
@@ -23,13 +24,15 @@ import org.jitsi.util.*;
public class SoundNotificationHandlerImpl
implements SoundNotificationHandler
{
- WeakHashMap<SCAudioClip, NotificationData> playedClips =
- new WeakHashMap<SCAudioClip, NotificationData>();
-
/**
- * If the sound is currently disabled.
+ * The indicator which determines whether this
+ * <tt>SoundNotificationHandler</tt> is currently muted i.e. the sounds are
+ * off.
*/
- private boolean isMute;
+ private boolean mute;
+
+ private Map<SCAudioClip, NotificationData> playedClips
+ = new WeakHashMap<SCAudioClip, NotificationData>();
/**
* {@inheritDoc}
@@ -40,55 +43,13 @@ public class SoundNotificationHandlerImpl
}
/**
- * Plays the sound given by the containing <tt>soundFileDescriptor</tt>. The
- * sound is played in loop if the loopInterval is defined.
- * @param action The action to act upon.
- * @param data Additional data for the event.
+ * Specifies if currently the sound is off.
+ *
+ * @return TRUE if currently the sound is off, FALSE otherwise
*/
- public void start(SoundNotificationAction action, NotificationData data)
+ public boolean isMute()
{
- if(isMute())
- return;
-
- boolean playOnlyOnPlayback = true;
-
- AudioNotifierService audioNotifService
- = NotificationActivator.getAudioNotifier();
- if(audioNotifService != null)
- playOnlyOnPlayback =
- audioNotifService.audioOutAndNotificationsShareSameDevice();
-
- if(playOnlyOnPlayback)
- {
- if(action.isSoundNotificationEnabled()
- || action.isSoundPlaybackEnabled())
- {
- play(action, data, true);
- }
- }
- else
- {
- if(action.isSoundNotificationEnabled())
- {
- play(action, data, false);
- }
-
- if(action.isSoundPlaybackEnabled())
- {
- play(action, data, true);
- }
- }
-
- if(action.isSoundPCSpeakerEnabled())
- {
- PCSpeakerClip audio = new PCSpeakerClip();
- playedClips.put(audio, data);
-
- if(action.getLoopInterval() > -1)
- audio.playInLoop(action.getLoopInterval());
- else
- audio.play();
- }
+ return mute;
}
/**
@@ -96,16 +57,18 @@ public class SoundNotificationHandlerImpl
* sound is played in loop if the loopInterval is defined.
* @param action The action to act upon.
* @param data Additional data for the event.
- * @param playback to use or not the playback or notification device.
+ * @param device
*/
- private void play(SoundNotificationAction action, NotificationData data,
- boolean playback)
+ private void play(
+ SoundNotificationAction action,
+ NotificationData data,
+ SCAudioClipDevice device)
{
AudioNotifierService audioNotifService
= NotificationActivator.getAudioNotifier();
- if(audioNotifService == null
- || StringUtils.isNullOrEmpty(action.getDescriptor(), true))
+ if((audioNotifService == null)
+ || StringUtils.isNullOrEmpty(action.getDescriptor(), true))
return;
// this is hack, seen on some os (particularly seen on macosx with
@@ -113,51 +76,42 @@ public class SoundNotificationHandlerImpl
// when playing notification in the call, can break the call and
// no further communicating can be done after the notification.
// So we skip playing notification if we have a call running
- if(playback)
+ if(SCAudioClipDevice.PLAYBACK.equals(device))
{
UIService uiService = NotificationActivator.getUIService();
+
if(uiService.getInProgressCalls().size() > 0)
- {
return;
- }
}
- SCAudioClip audio = audioNotifService
- .createAudio(action.getDescriptor(), playback);
+ SCAudioClip audio = null;
+
+ switch (device)
+ {
+ case NOTIFICATION:
+ case PLAYBACK:
+ audio = audioNotifService.createAudio(action.getDescriptor(), SCAudioClipDevice.PLAYBACK.equals(device));
+ break;
+
+ case PC_SPEAKER:
+ audio = new PCSpeakerClip();
+ break;
+ }
// it is possible that audio cannot be created
if(audio == null)
return;
playedClips.put(audio, data);
- if(action.getLoopInterval() > -1)
- audio.playInLoop(action.getLoopInterval());
- else
- audio.play();
- }
- /**
- * Stops the sound.
- * @param data Additional data for the event.
- */
- public void stop(NotificationData data)
- {
- AudioNotifierService audioNotifService
- = NotificationActivator.getAudioNotifier();
-
- if(audioNotifService == null)
- return;
+ @SuppressWarnings("unchecked")
+ Callable<Boolean> loopCondition
+ = (Callable<Boolean>)
+ data.getExtra(
+ NotificationData
+ .SOUND_NOTIFICATION_HANDLER_LOOP_CONDITION_EXTRA);
- for (Map.Entry<SCAudioClip, NotificationData> entry : playedClips
- .entrySet())
- {
- if(entry.getValue() == data)
- {
- SCAudioClip audio = entry.getKey();
- audio.stop();
- audioNotifService.destroyAudio(audio);
- }
- }
+ audio.play(action.getLoopInterval(), loopCondition);
}
/**
@@ -167,7 +121,7 @@ public class SoundNotificationHandlerImpl
*/
public void setMute(boolean isMute)
{
- this.isMute = isMute;
+ this.mute = isMute;
if(isMute)
{
@@ -189,182 +143,117 @@ public class SoundNotificationHandlerImpl
}
/**
- * Specifies if currently the sound is off.
- *
- * @return TRUE if currently the sound is off, FALSE otherwise
- */
- public boolean isMute()
- {
- return isMute;
- }
-
- /**
- * Plays beep on the pc speaker.
+ * Plays the sound given by the containing <tt>soundFileDescriptor</tt>. The
+ * sound is played in loop if the loopInterval is defined.
+ * @param action The action to act upon.
+ * @param data Additional data for the event.
*/
- private class PCSpeakerClip
- implements SCAudioClip
+ public void start(SoundNotificationAction action, NotificationData data)
{
- /**
- * Synching start/stop.
- */
- private final Object syncObject = new Object();
-
- /**
- * Is beep started.
- */
- private boolean started = false;
+ if(isMute())
+ return;
- /**
- * Is looping.
- */
- private boolean isLooping;
+ boolean playOnlyOnPlayback = true;
- /**
- * The interval to loop.
- */
- private int loopInterval;
+ AudioNotifierService audioNotifService
+ = NotificationActivator.getAudioNotifier();
- /**
- * Plays this audio.
- */
- public void play()
+ if(audioNotifService != null)
{
- started = true;
- new Thread("Playing beep:" + this.getClass())
- {
- @Override
- public void run()
- {
- runInPlayThread();
- }
- }.start();
+ playOnlyOnPlayback
+ = audioNotifService.audioOutAndNotificationsShareSameDevice();
}
- /**
- * Plays this audio in loop.
- *
- * @param silenceInterval interval between loops
- */
- public void playInLoop(int silenceInterval)
+ if(playOnlyOnPlayback)
{
- setLoopInterval(silenceInterval);
- setIsLooping(true);
-
- play();
+ if(action.isSoundNotificationEnabled()
+ || action.isSoundPlaybackEnabled())
+ {
+ play(action, data, SCAudioClipDevice.PLAYBACK);
+ }
}
-
- /**
- * Stops this audio.
- */
- public void stop()
+ else
{
- internalStop();
- setIsLooping(false);
+ if(action.isSoundNotificationEnabled())
+ play(action, data, SCAudioClipDevice.NOTIFICATION);
+ if(action.isSoundPlaybackEnabled())
+ play(action, data, SCAudioClipDevice.PLAYBACK);
}
- /**
- * Stops this audio without setting the isLooping property in the case of
- * a looping audio.
- */
- public void internalStop()
+ if(action.isSoundPCSpeakerEnabled())
+ play(action, data, SCAudioClipDevice.PC_SPEAKER);
+ }
+
+ /**
+ * Stops the sound.
+ * @param data Additional data for the event.
+ */
+ public void stop(NotificationData data)
+ {
+ AudioNotifierService audioNotifService
+ = NotificationActivator.getAudioNotifier();
+
+ if(audioNotifService == null)
+ return;
+
+ for (Map.Entry<SCAudioClip, NotificationData> entry
+ : playedClips.entrySet())
{
- synchronized (syncObject)
+ if(entry.getValue() == data)
{
- if (started)
- {
- started = false;
- syncObject.notifyAll();
- }
+ SCAudioClip audio = entry.getKey();
+
+ audio.stop();
+ audioNotifService.destroyAudio(audio);
}
}
+ }
+ /**
+ * Beeps the PC speaker.
+ */
+ private static class PCSpeakerClip
+ extends AbstractSCAudioClip
+ {
/**
- * Runs in a separate thread to perform the actual playback.
+ * Initializes a new <tt>PCSpeakerClip</tt> instance.
*/
- private void runInPlayThread()
+ public PCSpeakerClip()
{
- while (started)
- {
- if (!runOnceInPlayThread())
- break;
-
- if(isLooping())
- {
- synchronized(syncObject)
- {
- if (started)
- {
- try
- {
- if(getLoopInterval() > 0)
- syncObject.wait(getLoopInterval());
- }
- catch (InterruptedException e)
- {
- }
- }
- }
- }
- else
- break;
- }
+ super(null, NotificationActivator.getAudioNotifier());
}
/**
- * Beeps.
+ * Beeps the PC speaker.
*
- * @return <tt>true</tt> if the playback was successful;
- * otherwise, <tt>false</tt>
+ * @return <tt>true</tt> if the playback was successful; otherwise,
+ * <tt>false</tt>
*/
- private boolean runOnceInPlayThread()
+ protected boolean runOnceInPlayThread()
{
try
{
Toolkit.getDefaultToolkit().beep();
+ return true;
}
catch (Throwable t)
{
- //logger.error("Failed to get audio stream " + url, ioex);
- return false;
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
+ return false;
}
-
- return true;
- }
-
- /**
- * Returns TRUE if this audio is currently playing in loop,
- * FALSE otherwise.
- * @return TRUE if this audio is currently playing in loop,
- * FALSE otherwise.
- */
- public boolean isLooping()
- {
- return isLooping;
- }
-
- /**
- * Returns the loop interval if this audio is looping.
- * @return the loop interval if this audio is looping
- */
- public int getLoopInterval()
- {
- return loopInterval;
- }
-
- /**
- * @param isLooping the isLooping to set
- */
- public void setIsLooping(boolean isLooping)
- {
- this.isLooping = isLooping;
}
+ }
- /**
- * @param loopInterval the loopInterval to set
- */
- public void setLoopInterval(int loopInterval)
- {
- this.loopInterval = loopInterval;
- }
+ /**
+ * Enumerates the types of devices on which <tt>SCAudioClip</tt>s may be
+ * played back.
+ */
+ private static enum SCAudioClipDevice
+ {
+ NOTIFICATION,
+ PC_SPEAKER,
+ PLAYBACK
}
}
diff --git a/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java b/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java
index e5db2e6..1c1d162 100644
--- a/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java
@@ -474,22 +474,19 @@ public class LoggingConfigForm
if(notificationService != null)
{
- String bodyMsgKey = null;
-
- if(dest != null)
- bodyMsgKey = "plugin.loggingutils.ARCHIVE_MESSAGE_OK";
- else
- bodyMsgKey = "plugin.loggingutils.ARCHIVE_MESSAGE_NOTOK";
+ String bodyMsgKey
+ = (dest == null)
+ ? "plugin.loggingutils.ARCHIVE_MESSAGE_NOTOK"
+ : "plugin.loggingutils.ARCHIVE_MESSAGE_OK";
notificationService.fireNotification(
- LOGFILES_ARCHIVED,
- resources.getI18NString(
- "plugin.loggingutils.ARCHIVE_BUTTON"),
- resources.getI18NString(
- bodyMsgKey,
- new String[]{dest.getAbsolutePath()}),
- null,
- null);
+ LOGFILES_ARCHIVED,
+ resources.getI18NString(
+ "plugin.loggingutils.ARCHIVE_BUTTON"),
+ resources.getI18NString(
+ bodyMsgKey,
+ new String[]{dest.getAbsolutePath()}),
+ null);
}
}
@@ -721,20 +718,18 @@ public class LoggingConfigForm
if(notificationService != null)
{
+ ResourceManagementService resources
+ = LoggingUtilsActivator.getResourceService();
String bodyMsgKey = "plugin.loggingutils.ARCHIVE_MESSAGE_OK";
- ResourceManagementService resources =
- LoggingUtilsActivator.getResourceService();
-
notificationService.fireNotification(
- LOGFILES_ARCHIVED,
- resources.getI18NString(
- "plugin.loggingutils.ARCHIVE_BUTTON"),
- resources.getI18NString(
- bodyMsgKey,
- new String[]{uploadLocation}),
- null,
- null);
+ LOGFILES_ARCHIVED,
+ resources.getI18NString(
+ "plugin.loggingutils.ARCHIVE_BUTTON"),
+ resources.getI18NString(
+ bodyMsgKey,
+ new String[]{uploadLocation}),
+ null);
}
}
}
diff --git a/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java b/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java
index 4aa9cb1..d2022e3 100644
--- a/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java
+++ b/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java
@@ -9,6 +9,7 @@ package net.java.sip.communicator.plugin.notificationwiring;
import java.awt.image.*;
import java.net.*;
import java.util.*;
+import java.util.concurrent.*;
import javax.imageio.*;
@@ -22,61 +23,36 @@ import net.java.sip.communicator.util.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.service.protocol.event.*;
+import org.jitsi.service.resources.*;
import org.osgi.framework.*;
/**
- * Listens for all kinds of events and triggers when needed a notification,
- * a popup or sound one or other.
+ * Listens to various events which are related to the display and/or playback of
+ * notifications and shows/starts or hides/stops the notifications in question.
+ *
* @author Damian Minkov
+ * @author Lyubomir Marinov
*/
public class NotificationManager
- implements MessageListener,
- ServiceListener,
- FileTransferListener,
- TypingNotificationsListener,
- CallListener,
+ implements AdHocChatRoomMessageListener,
CallChangeListener,
+ CallListener,
+ CallPeerConferenceListener,
CallPeerListener,
CallPeerSecurityListener,
ChatRoomMessageListener,
- LocalUserChatRoomPresenceListener,
+ FileTransferListener,
LocalUserAdHocChatRoomPresenceListener,
- AdHocChatRoomMessageListener,
- CallPeerConferenceListener,
- Recorder.Listener
+ LocalUserChatRoomPresenceListener,
+ MessageListener,
+ Recorder.Listener,
+ ServiceListener,
+ TypingNotificationsListener
{
/**
- * Our logger.
- */
- private static final Logger logger =
- Logger.getLogger(NotificationManager.class);
-
- /**
- * The image used, when a contact has no photo specified.
- */
- public static final ImageID DEFAULT_USER_PHOTO
- = new ImageID("service.gui.DEFAULT_USER_PHOTO");
-
- /**
- * Stores all already loaded images.
- */
- private static final Map<ImageID, BufferedImage> loadedImages =
- new Hashtable<ImageID, BufferedImage>();
-
- /**
- * Pseudo timer used to delay multiple typings notifications before
- * receiving the message.
- *
- * Time to live : 1 minute
- */
- private Map<Contact,Long> proactiveTimer = new HashMap<Contact, Long>();
-
- /**
- * Stores notification references to stop them if a notification has expired
- * (e.g. to stop the dialing sound).
+ * Default event type for a busy call.
*/
- private Map<Call, NotificationData> callNotifications =
- new WeakHashMap<Call, NotificationData>();
+ public static final String BUSY_CALL = "BusyCall";
/**
* Default event type for call been saved using a recorder.
@@ -84,11 +60,6 @@ public class NotificationManager
public static final String CALL_SAVED = "CallSaved";
/**
- * Default event type for incoming file transfers.
- */
- public static final String INCOMING_FILE = "IncomingFile";
-
- /**
* Default event type for security error on a call.
*/
public static final String CALL_SECURITY_ERROR = "CallSecurityError";
@@ -99,15 +70,15 @@ public class NotificationManager
public static final String CALL_SECURITY_ON = "CallSecurityOn";
/**
- * Default event type when a secure message received.
+ * The image used, when a contact has no photo specified.
*/
- public static final String SECURITY_MESSAGE = "SecurityMessage";
+ public static final ImageID DEFAULT_USER_PHOTO
+ = new ImageID("service.gui.DEFAULT_USER_PHOTO");
/**
- * Default event type for
- * proactive notifications (typing notifications when chatting).
+ * Default event type for dialing.
*/
- public static final String PROACTIVE_NOTIFICATION = "ProactiveNotification";
+ public static final String DIALING = "Dialing";
/**
* Default event type for hanging up calls.
@@ -115,24 +86,22 @@ public class NotificationManager
public static final String HANG_UP = "HangUp";
/**
- * Default event type for dialing.
- */
- public static final String DIALING = "Dialing";
-
- /**
- * Default event type for a busy call.
+ * The cache of <tt>BufferedImage</tt> instances which we have already
+ * loaded by <tt>ImageID</tt> and which we store so that we do not have to
+ * load them again.
*/
- public static final String BUSY_CALL = "BusyCall";
+ private static final Map<ImageID, BufferedImage> images
+ = new Hashtable<ImageID, BufferedImage>();
/**
- * Default event type for outgoing calls.
+ * Default event type for receiving calls (incoming calls).
*/
- public static final String OUTGOING_CALL = "OutgoingCall";
+ public static final String INCOMING_CALL = "IncomingCall";
/**
- * Default event type for receiving calls (incoming calls).
+ * Default event type for incoming file transfers.
*/
- public static final String INCOMING_CALL = "IncomingCall";
+ public static final String INCOMING_FILE = "IncomingFile";
/**
* Default event type for receiving messages.
@@ -140,29 +109,42 @@ public class NotificationManager
public static final String INCOMING_MESSAGE = "IncomingMessage";
/**
- * Initialize, register default notifications and start listening for
- * new protocols or removed one and find any that are already registered.
+ * The <tt>Logger</tt> used by the <tt>NotificationManager</tt> class and
+ * its instances for logging output.
*/
- void init()
- {
- registerDefaultNotifications();
+ private static final Logger logger
+ = Logger.getLogger(NotificationManager.class);
- // listens for new protocols
- NotificationWiringActivator.bundleContext.addServiceListener(this);
+ /**
+ * Default event type for outgoing calls.
+ */
+ public static final String OUTGOING_CALL = "OutgoingCall";
- // enumerate currently registered protocols
- for(ProtocolProviderService pp : getProtocolProviders())
- {
- handleProviderAdded(pp);
- }
+ /**
+ * Default event type for
+ * proactive notifications (typing notifications when chatting).
+ */
+ public static final String PROACTIVE_NOTIFICATION = "ProactiveNotification";
- NotificationWiringActivator.getMediaService().addRecorderListener(this);
- }
+ /**
+ * Default event type when a secure message received.
+ */
+ public static final String SECURITY_MESSAGE = "SecurityMessage";
/**
- * Register all default notifications.
+ * Fires a chat message notification for the given event type through the
+ * <tt>NotificationService</tt>.
+ *
+ * @param chatContact the chat contact to which the chat message corresponds;
+ * the chat contact could be a Contact or a ChatRoom.
+ * @param eventType the event type for which we fire a notification
+ * @param messageTitle the title of the message
+ * @param message the content of the message
*/
- private void registerDefaultNotifications()
+ public static void fireChatNotification(Object chatContact,
+ String eventType,
+ String messageTitle,
+ String message)
{
NotificationService notificationService
= NotificationWiringActivator.getNotificationService();
@@ -170,116 +152,232 @@ public class NotificationManager
if(notificationService == null)
return;
- // Register incoming message notifications.
- notificationService.registerDefaultNotificationForEvent(
- INCOMING_MESSAGE,
- NotificationAction.ACTION_POPUP_MESSAGE,
- null,
- null);
+ NotificationAction popupActionHandler = null;
+ UIService uiService = NotificationWiringActivator.getUIService();
- notificationService.registerDefaultNotificationForEvent(
- INCOMING_MESSAGE,
- new SoundNotificationAction(
- SoundProperties.INCOMING_MESSAGE, -1, true, false, false));
+ Chat chatPanel = null;
+ byte[] contactIcon = null;
+ if (chatContact instanceof Contact)
+ {
+ Contact contact = (Contact) chatContact;
- // Register incoming call notifications.
- notificationService.registerDefaultNotificationForEvent(
- INCOMING_CALL,
- NotificationAction.ACTION_POPUP_MESSAGE,
- null,
- null);
+ if(uiService != null)
+ chatPanel = uiService.getChat(contact);
- SoundNotificationAction inCallSoundHandler
- = new SoundNotificationAction(
- SoundProperties.INCOMING_CALL, 2000, true, true, true);
+ contactIcon = contact.getImage();
+ if(contactIcon == null)
+ {
+ contactIcon =
+ ImageUtils.toByteArray(getImage(DEFAULT_USER_PHOTO));
+ }
+ }
+ else if (chatContact instanceof ChatRoom)
+ {
+ ChatRoom chatRoom = (ChatRoom) chatContact;
- notificationService.registerDefaultNotificationForEvent(
- INCOMING_CALL,
- inCallSoundHandler);
+ // For system rooms we don't want to send notification events.
+ if (chatRoom.isSystem())
+ return;
- // Register outgoing call notifications.
- SoundNotificationAction outCallSoundHandler
- = new SoundNotificationAction(
- SoundProperties.OUTGOING_CALL, 3000, false, true, false);
+ if(uiService != null)
+ chatPanel = uiService.getChat(chatRoom);
+ }
- notificationService.registerDefaultNotificationForEvent(
- OUTGOING_CALL,
- outCallSoundHandler);
+ if (chatPanel != null)
+ {
+ if (eventType.equals(INCOMING_MESSAGE)
+ && chatPanel.isChatFocused())
+ {
+ popupActionHandler = notificationService
+ .getEventNotificationAction(eventType,
+ NotificationAction.ACTION_POPUP_MESSAGE);
- // Register busy call notifications.
- SoundNotificationAction busyCallSoundHandler
- = new SoundNotificationAction(SoundProperties.BUSY, 1,
- false, true, false);
+ popupActionHandler.setEnabled(false);
+ }
+ }
- notificationService.registerDefaultNotificationForEvent(
- BUSY_CALL,
- busyCallSoundHandler);
+ Map<String,Object> extras = new HashMap<String,Object>();
- // Register dial notifications.
- SoundNotificationAction dialSoundHandler
- = new SoundNotificationAction(
- SoundProperties.DIALING, -1, false, true, false);
+ extras.put(
+ NotificationData.POPUP_MESSAGE_HANDLER_TAG_EXTRA,
+ chatContact);
+ notificationService.fireNotification(
+ eventType,
+ messageTitle,
+ message,
+ contactIcon,
+ extras);
- notificationService.registerDefaultNotificationForEvent(
- DIALING,
- dialSoundHandler);
+ if(popupActionHandler != null)
+ popupActionHandler.setEnabled(true);
+ }
- // Register the hangup sound notification.
- SoundNotificationAction hangupSoundHandler
- = new SoundNotificationAction(
- SoundProperties.HANG_UP, -1, false, true, false);
+ /**
+ * Fires a notification for the given event type through the
+ * <tt>NotificationService</tt>. The event type is one of the static
+ * constants defined in the <tt>NotificationManager</tt> class.
+ * <p>
+ * <b>Note</b>: The uses of the method at the time of this writing do not
+ * take measures to stop looping sounds if the respective notifications use
+ * them i.e. there is implicit agreement that the notifications fired
+ * through the method do not loop sounds. Consequently, the method passes
+ * arguments to <tt>NotificationService</tt> so that sounds are played once
+ * only.
+ * </p>
+ *
+ * @param eventType the event type for which we want to fire a notification
+ */
+ private static void fireNotification(String eventType)
+ {
+ NotificationService notificationService
+ = NotificationWiringActivator.getNotificationService();
- notificationService.registerDefaultNotificationForEvent(
- HANG_UP,
- hangupSoundHandler);
+ if (notificationService != null)
+ notificationService.fireNotification(eventType);
+ }
- // Register proactive notifications.
- notificationService.registerDefaultNotificationForEvent(
- PROACTIVE_NOTIFICATION,
- NotificationAction.ACTION_POPUP_MESSAGE,
- null,
- null);
+ /**
+ * Fires a notification for the given event type through the
+ * <tt>NotificationService</tt>. The event type is one of the static
+ * constants defined in the <tt>NotificationManager</tt> class.
+ *
+ * @param eventType the event type for which we want to fire a notification
+ * @param loopCondition the method which will determine whether any sounds
+ * played as part of the specified notification will continue looping
+ * @return a reference to the fired notification to stop it.
+ */
+ private static NotificationData fireNotification(
+ String eventType,
+ Callable<Boolean> loopCondition)
+ {
+ return fireNotification(eventType, null, null, null, loopCondition);
+ }
- // Register warning message notifications.
- notificationService.registerDefaultNotificationForEvent(
- SECURITY_MESSAGE,
- NotificationAction.ACTION_POPUP_MESSAGE,
- null,
- null);
+ /**
+ * Fires a notification through the <tt>NotificationService</tt> with a
+ * specific event type, a specific message title and a specific message.
+ * <p>
+ * <b>Note</b>: The uses of the method at the time of this writing do not
+ * take measures to stop looping sounds if the respective notifications use
+ * them i.e. there is implicit agreement that the notifications fired
+ * through the method do not loop sounds. Consequently, the method passes
+ * arguments to <tt>NotificationService</tt> so that sounds are played once
+ * only.
+ * </p>
+ *
+ * @param eventType the event type of the notification to be fired
+ * @param messageTitle the title of the message to be displayed by the
+ * notification to be fired if such a display is supported
+ * @param message the message to be displayed by the notification to be
+ * fired if such a display is supported
+ */
+ private static void fireNotification(
+ String eventType,
+ String messageTitle,
+ String message)
+ {
+ NotificationService notificationService
+ = NotificationWiringActivator.getNotificationService();
- // Register sound notification for security state on during a call.
- notificationService.registerDefaultNotificationForEvent(
- CALL_SECURITY_ON,
- new SoundNotificationAction(
- SoundProperties.CALL_SECURITY_ON, -1,
- false, true, false));
+ if (notificationService != null)
+ {
+ notificationService.fireNotification(
+ eventType,
+ messageTitle,
+ message,
+ null);
+ }
+ }
- // Register sound notification for security state off during a call.
- notificationService.registerDefaultNotificationForEvent(
- CALL_SECURITY_ERROR,
- new SoundNotificationAction(
- SoundProperties.CALL_SECURITY_ERROR, -1,
- false, true, false));
+ /**
+ * Fires a message notification for the given event type through the
+ * <tt>NotificationService</tt>.
+ *
+ * @param eventType the event type for which we fire a notification
+ * @param messageTitle the title of the message
+ * @param message the content of the message
+ * @param cmdargs the value to be provided to
+ * {@link CommandNotificationHandler#execute(CommandNotificationAction,
+ * Map)} as the <tt>cmdargs</tt> argument
+ * @param loopCondition the method which will determine whether any sounds
+ * played as part of the specified notification will continue looping
+ * @return a reference to the fired notification to stop it.
+ */
+ private static NotificationData fireNotification(
+ String eventType,
+ String messageTitle,
+ String message,
+ Map<String,String> cmdargs,
+ Callable<Boolean> loopCondition)
+ {
+ NotificationService notificationService
+ = NotificationWiringActivator.getNotificationService();
- // Register sound notification for incoming files.
- notificationService.registerDefaultNotificationForEvent(
- INCOMING_FILE,
- NotificationAction.ACTION_POPUP_MESSAGE,
- null,
- null);
+ if (notificationService == null)
+ return null;
+ else
+ {
+ Map<String,Object> extras = new HashMap<String,Object>();
- notificationService.registerDefaultNotificationForEvent(
- INCOMING_FILE,
- new SoundNotificationAction(
- SoundProperties.INCOMING_FILE, -1,
- true, false, false));
+ if (cmdargs != null)
+ {
+ extras.put(
+ NotificationData
+ .COMMAND_NOTIFICATION_HANDLER_CMDARGS_EXTRA,
+ cmdargs);
+ }
+ if (loopCondition != null)
+ {
+ extras.put(
+ NotificationData
+ .SOUND_NOTIFICATION_HANDLER_LOOP_CONDITION_EXTRA,
+ loopCondition);
+ }
+ return
+ notificationService.fireNotification(
+ eventType,
+ messageTitle,
+ message,
+ null,
+ extras);
+ }
+ }
- // Register notification for saved calls.
- notificationService.registerDefaultNotificationForEvent(
- CALL_SAVED,
- NotificationAction.ACTION_POPUP_MESSAGE,
- null,
- null);
+ /**
+ * Loads an image from a given image identifier.
+ *
+ * @param imageID The identifier of the image.
+ * @return The image for the given identifier.
+ */
+ public static BufferedImage getImage(ImageID imageID)
+ {
+ /*
+ * If we were mapping ImageID to null, we would be using the method
+ * Map.containsKey. However, that does not seem to be the case.
+ */
+ BufferedImage image = images.get(imageID);
+
+ if (image == null)
+ {
+ URL path
+ = NotificationWiringActivator.getResources().getImageURL(
+ imageID.getId());
+
+ if (path != null)
+ {
+ try
+ {
+ image = ImageIO.read(path);
+ images.put(imageID, image);
+ }
+ catch (Exception ex)
+ {
+ logger.error("Failed to load image: " + path, ex);
+ }
+ }
+ }
+
+ return image;
}
/**
@@ -364,6 +462,226 @@ public class NotificationManager
}
/**
+ * Determines whether a specific <code>ChatRoom</code> is private i.e.
+ * represents a one-to-one conversation which is not a channel. Since the
+ * interface {@link ChatRoom} does not expose the private property, an
+ * heuristic is used as a workaround: (1) a system <code>ChatRoom</code> is
+ * obviously not private and (2) a <code>ChatRoom</code> is private if it
+ * has only one <code>ChatRoomMember</code> who is not the local user.
+ *
+ * @param chatRoom
+ * the <code>ChatRoom</code> to be determined as private or not
+ * @return <tt>true</tt> if the specified <code>ChatRoom</code> is private;
+ * otherwise, <tt>false</tt>
+ */
+ private static boolean isPrivate(ChatRoom chatRoom)
+ {
+ if (!chatRoom.isSystem()
+ && chatRoom.isJoined()
+ && (chatRoom.getMembersCount() == 1))
+ {
+ String nickname = chatRoom.getUserNickname();
+
+ if (nickname != null)
+ {
+ for (ChatRoomMember member : chatRoom.getMembers())
+ if (nickname.equals(member.getName()))
+ return false;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Stops all sounds for the given event type.
+ *
+ * @param data the event type for which we should stop sounds. One of
+ * the static event types defined in this class.
+ */
+ public static void stopSound(NotificationData data)
+ {
+ NotificationService notificationService
+ = NotificationWiringActivator.getNotificationService();
+
+ if(notificationService != null)
+ notificationService.stopNotification(data);
+ }
+
+ /**
+ * Stores notification references to stop them if a notification has expired
+ * (e.g. to stop the dialing sound).
+ */
+ private final Map<Call, NotificationData> callNotifications
+ = new WeakHashMap<Call, NotificationData>();
+
+ /**
+ * The pseudo timer which is used to delay multiple typing notifications
+ * before receiving the message.
+ */
+ private final Map<Contact, Long> proactiveTimer
+ = new HashMap<Contact, Long>();
+
+ /**
+ * Implements CallListener.callEnded. Stops sounds that are playing at
+ * the moment if there're any.
+ * @param event the <tt>CallEvent</tt>
+ */
+ public void callEnded(CallEvent event)
+ {
+ try
+ {
+ // Stop all telephony related sounds.
+// stopAllTelephonySounds();
+ stopSound(callNotifications.get(event.getSourceCall()));
+
+ // Play the hangup sound.
+ fireNotification(HANG_UP);
+ }
+ catch(Throwable t)
+ {
+ logger.error("Error notifying for call ended", t);
+ }
+ }
+
+ /**
+ * Implements the <tt>CallChangeListener.callPeerAdded</tt> method.
+ * @param evt the <tt>CallPeerEvent</tt> that notifies us for the change
+ */
+ public void callPeerAdded(CallPeerEvent evt)
+ {
+ CallPeer peer = evt.getSourceCallPeer();
+
+ if(peer == null)
+ return;
+
+ peer.addCallPeerListener(this);
+ peer.addCallPeerSecurityListener(this);
+ peer.addCallPeerConferenceListener(this);
+ }
+
+ /**
+ * Implements the <tt>CallChangeListener.callPeerRemoved</tt> method.
+ * @param evt the <tt>CallPeerEvent</tt> that has been triggered
+ */
+ public void callPeerRemoved(CallPeerEvent evt)
+ {
+ CallPeer peer = evt.getSourceCallPeer();
+
+ if(peer == null)
+ return;
+
+ peer.removeCallPeerListener(this);
+ peer.removeCallPeerSecurityListener(this);
+ peer.addCallPeerConferenceListener(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Not used.
+ */
+ public void callStateChanged(CallChangeEvent ev) {}
+
+ /**
+ * {@inheritDoc}
+ *
+ * Not used.
+ */
+ public void conferenceFocusChanged(CallPeerConferenceEvent ev) {}
+
+ /**
+ * Indicates that the given conference member has been added to the given
+ * peer.
+ *
+ * @param conferenceEvent the event
+ */
+ public void conferenceMemberAdded(CallPeerConferenceEvent conferenceEvent)
+ {
+ try
+ {
+ CallPeer peer
+ = conferenceEvent
+ .getConferenceMember()
+ .getConferenceFocusCallPeer();
+
+ if(peer.getConferenceMemberCount() > 0)
+ {
+ CallPeerSecurityStatusEvent securityEvent
+ = peer.getCurrentSecuritySettings();
+
+ if (securityEvent instanceof CallPeerSecurityOnEvent)
+ fireNotification(CALL_SECURITY_ON);
+ }
+ }
+ catch(Throwable t)
+ {
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
+ logger.error("Error notifying for secured call member", t);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Not used.
+ */
+ public void conferenceMemberRemoved(CallPeerConferenceEvent ev) {}
+
+ /**
+ * {@inheritDoc}
+ *
+ * Not used.
+ */
+ public void fileTransferCreated(FileTransferCreatedEvent ev) {}
+
+ /**
+ * {@inheritDoc}
+ *
+ * Not used.
+ */
+ public void fileTransferRequestCanceled(FileTransferRequestEvent ev) {}
+
+ /**
+ * When a request has been received we show a notification.
+ *
+ * @param event <tt>FileTransferRequestEvent</tt>
+ * @see FileTransferListener#fileTransferRequestReceived(FileTransferRequestEvent)
+ */
+ public void fileTransferRequestReceived(FileTransferRequestEvent event)
+ {
+ try
+ {
+ IncomingFileTransferRequest request = event.getRequest();
+ Contact sourceContact = request.getSender();
+
+ //Fire notification
+ String title = NotificationWiringActivator.getResources().getI18NString(
+ "service.gui.FILE_RECEIVING_FROM",
+ new String[]{sourceContact.getDisplayName()});
+
+ fireChatNotification(
+ sourceContact,
+ INCOMING_FILE,
+ title,
+ request.getFileName());
+ }
+ catch(Throwable t)
+ {
+ logger.error("Error notifying for file transfer req received", t);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Not used.
+ */
+ public void fileTransferRequestRejected(FileTransferRequestEvent ev) {}
+
+ /**
* Adds all listeners related to the given protocol provider.
*
* @param protocolProvider the <tt>ProtocolProviderService</tt>
@@ -517,245 +835,105 @@ public class NotificationManager
}
/**
- * Implements the <tt>ServiceListener</tt> method. Verifies whether the
- * passed event concerns a <tt>ProtocolProviderService</tt> and adds the
- * corresponding listeners.
- *
- * @param event The <tt>ServiceEvent</tt> object.
- */
- public void serviceChanged(ServiceEvent event)
- {
- ServiceReference serviceRef = event.getServiceReference();
-
- // if the event is caused by a bundle being stopped, we don't want to
- // know
- if (serviceRef.getBundle().getState() == Bundle.STOPPING)
- {
- return;
- }
-
- Object service =
- NotificationWiringActivator.bundleContext.getService(serviceRef);
-
- // we don't care if the source service is not a protocol provider
- if (!(service instanceof ProtocolProviderService))
- {
- return;
- }
-
- switch (event.getType())
- {
- case ServiceEvent.REGISTERED:
- this.handleProviderAdded((ProtocolProviderService) service);
- break;
- case ServiceEvent.UNREGISTERING:
- this.handleProviderRemoved((ProtocolProviderService) service);
- break;
- }
- }
-
- /**
- * Fires a message notification for the given event type through the
- * <tt>NotificationService</tt>.
- *
- * @param eventType the event type for which we fire a notification
- * @param messageTitle the title of the message
- * @param message the content of the message
- * @return A reference to the fired notification to stop it.
- */
- public static NotificationData fireNotification(String eventType,
- String messageTitle,
- String message)
- {
- NotificationService notificationService
- = NotificationWiringActivator.getNotificationService();
-
- if(notificationService == null)
- return null;
-
- return notificationService.fireNotification( eventType,
- messageTitle,
- message,
- null,
- null);
- }
-
- /**
- * Fires a message notification for the given event type through the
- * <tt>NotificationService</tt>.
- *
- * @param eventType the event type for which we fire a notification
- * @param messageTitle the title of the message
- * @param message the content of the message
- * @param extra additional event data for external processing
- * @return A reference to the fired notification to stop it.
- */
- public static NotificationData fireNotification(String eventType,
- String messageTitle,
- String message,
- Map<String,String> extra)
- {
- NotificationService notificationService
- = NotificationWiringActivator.getNotificationService();
-
- if(notificationService == null)
- return null;
-
- return notificationService.fireNotification(eventType,
- messageTitle,
- message,
- extra,
- null,
- null);
- }
-
- /**
- * Fires a chat message notification for the given event type through the
- * <tt>NotificationService</tt>.
+ * Implements CallListener.incomingCallReceived. When a call is received
+ * plays the ring phone sound to the user and gathers caller information
+ * that may be used by a user-specified command (incomingCall event
+ * trigger).
*
- * @param chatContact the chat contact to which the chat message corresponds;
- * the chat contact could be a Contact or a ChatRoom.
- * @param eventType the event type for which we fire a notification
- * @param messageTitle the title of the message
- * @param message the content of the message
+ * @param ev the <tt>CallEvent</tt>
*/
- public static void fireChatNotification(Object chatContact,
- String eventType,
- String messageTitle,
- String message)
+ public void incomingCallReceived(CallEvent ev)
{
- NotificationService notificationService
- = NotificationWiringActivator.getNotificationService();
-
- if(notificationService == null)
- return;
-
- NotificationAction popupActionHandler = null;
- UIService uiService = NotificationWiringActivator.getUIService();
-
- Chat chatPanel = null;
- byte[] contactIcon = null;
- if (chatContact instanceof Contact)
- {
- Contact contact = (Contact) chatContact;
-
- if(uiService != null)
- chatPanel = uiService.getChat(contact);
-
- contactIcon = contact.getImage();
- if(contactIcon == null)
- {
- contactIcon =
- ImageUtils.toByteArray(getImage(DEFAULT_USER_PHOTO));
- }
- }
- else if (chatContact instanceof ChatRoom)
+ try
{
- ChatRoom chatRoom = (ChatRoom) chatContact;
+ final Call call = ev.getSourceCall();
+ CallPeer peer = call.getCallPeers().next();
+ Map<String,String> peerInfo = new HashMap<String, String>();
+ String peerName = peer.getDisplayName();
+
+ peerInfo.put("caller.uri", peer.getURI());
+ peerInfo.put("caller.address", peer.getAddress());
+ peerInfo.put("caller.name", peerName);
+ peerInfo.put("caller.id", peer.getPeerID());
+
+ NotificationData notification
+ = fireNotification(
+ INCOMING_CALL,
+ "",
+ NotificationWiringActivator.getResources()
+ .getI18NString(
+ "service.gui.INCOMING_CALL",
+ new String[] { peerName }),
+ peerInfo,
+ new Callable<Boolean>()
+ {
+ public Boolean call()
+ {
+ /*
+ * INCOMING_CALL should be played for a Call
+ * only while there is a CallPeer in the
+ * INCOMING_CALL state.
+ */
+ Iterator<? extends CallPeer> peerIter
+ = call.getCallPeers();
+ boolean loop = false;
+
+ while (peerIter.hasNext())
+ {
+ CallPeer peer = peerIter.next();
+
+ if (CallPeerState.INCOMING_CALL.equals(
+ peer.getState()))
+ {
+ loop = true;
+ break;
+ }
+ }
+ return loop;
+ }
+ });
+
+ if (notification != null)
+ callNotifications.put(call, notification);
- // For system rooms we don't want to send notification events.
- if (chatRoom.isSystem())
- return;
+ call.addCallChangeListener(this);
- if(uiService != null)
- chatPanel = uiService.getChat(chatRoom);
+ peer.addCallPeerListener(this);
+ peer.addCallPeerSecurityListener(this);
+ peer.addCallPeerConferenceListener(this);
}
-
- if (chatPanel != null)
+ catch(Throwable t)
{
- if (eventType.equals(INCOMING_MESSAGE)
- && chatPanel.isChatFocused())
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
{
- popupActionHandler = notificationService
- .getEventNotificationAction(eventType,
- NotificationAction.ACTION_POPUP_MESSAGE);
-
- popupActionHandler.setEnabled(false);
+ logger.error(
+ "An error occurred while trying to notify"
+ + " about an incoming call",
+ t);
}
}
-
- notificationService.fireNotification( eventType,
- messageTitle,
- message,
- null,
- contactIcon,
- chatContact);
-
- if(popupActionHandler != null)
- popupActionHandler.setEnabled(true);
- }
-
- /**
- * Fires a notification for the given event type through the
- * <tt>NotificationService</tt>. The event type is one of the static
- * constants defined in this class.
- *
- * @param eventType the event type for which we want to fire a notification
- * @return A reference to the fired notification to stop it.
- */
- public static NotificationData fireNotification(String eventType)
- {
- NotificationService notificationService
- = NotificationWiringActivator.getNotificationService();
-
- if(notificationService == null)
- return null;
-
- return notificationService.fireNotification(eventType);
}
/**
- * Stops all sounds for the given event type.
- *
- * @param data the event type for which we should stop sounds. One of
- * the static event types defined in this class.
+ * Initialize, register default notifications and start listening for
+ * new protocols or removed one and find any that are already registered.
*/
- public static void stopSound(NotificationData data)
+ void init()
{
- NotificationService notificationService
- = NotificationWiringActivator.getNotificationService();
-
- if(notificationService == null)
- return;
-
- notificationService.stopNotification(data);
- }
+ registerDefaultNotifications();
- /**
- * Loads an image from a given image identifier.
- *
- * @param imageID The identifier of the image.
- * @return The image for the given identifier.
- */
- public static BufferedImage getImage(ImageID imageID)
- {
- BufferedImage image = null;
+ // listens for new protocols
+ NotificationWiringActivator.bundleContext.addServiceListener(this);
- if (loadedImages.containsKey(imageID))
- {
- image = loadedImages.get(imageID);
- }
- else
+ // enumerate currently registered protocols
+ for(ProtocolProviderService pp : getProtocolProviders())
{
- URL path = NotificationWiringActivator.getResources()
- .getImageURL(imageID.getId());
-
- if (path != null)
- {
- try
- {
- image = ImageIO.read(path);
-
- loadedImages.put(imageID, image);
- }
- catch (Exception ex)
- {
- logger.error("Failed to load image: " + path, ex);
- }
- }
+ handleProviderAdded(pp);
}
- return image;
+ NotificationWiringActivator.getMediaService().addRecorderListener(this);
}
/**
@@ -793,268 +971,238 @@ public class NotificationManager
}
/**
- * Determines whether a specific <code>ChatRoom</code> is private i.e.
- * represents a one-to-one conversation which is not a channel. Since the
- * interface {@link ChatRoom} does not expose the private property, an
- * heuristic is used as a workaround: (1) a system <code>ChatRoom</code> is
- * obviously not private and (2) a <code>ChatRoom</code> is private if it
- * has only one <code>ChatRoomMember</code> who is not the local user.
+ * Implements the
+ * <tt>LocalUserAdHocChatRoomPresenceListener.localUserPresenceChanged</tt>
+ * method
*
- * @param chatRoom
- * the <code>ChatRoom</code> to be determined as private or not
- * @return <tt>true</tt> if the specified <code>ChatRoom</code> is private;
- * otherwise, <tt>false</tt>
+ * @param evt the <tt>LocalUserAdHocChatRoomPresenceChangeEvent</tt> that
+ * notified us of a presence change
*/
- private static boolean isPrivate(ChatRoom chatRoom)
+ public void localUserAdHocPresenceChanged(
+ LocalUserAdHocChatRoomPresenceChangeEvent evt)
{
- if (!chatRoom.isSystem()
- && chatRoom.isJoined()
- && (chatRoom.getMembersCount() == 1))
- {
- String nickname = chatRoom.getUserNickname();
+ String eventType = evt.getEventType();
- if (nickname != null)
- {
- for (ChatRoomMember member : chatRoom.getMembers())
- if (nickname.equals(member.getName()))
- return false;
- return true;
- }
+ if (LocalUserAdHocChatRoomPresenceChangeEvent
+ .LOCAL_USER_JOINED.equals(eventType))
+ {
+ evt.getAdHocChatRoom().addMessageListener(this);
+ }
+ else if (LocalUserAdHocChatRoomPresenceChangeEvent
+ .LOCAL_USER_LEFT.equals(eventType)
+ || LocalUserAdHocChatRoomPresenceChangeEvent
+ .LOCAL_USER_DROPPED.equals(eventType))
+ {
+ evt.getAdHocChatRoom().removeMessageListener(this);
}
- return false;
}
/**
- * Fired on new messages.
- * @param evt the <tt>MessageReceivedEvent</tt> containing
- * details on the received message
+ * Implements the
+ * <tt>LocalUserChatRoomPresenceListener.localUserPresenceChanged</tt>
+ * method.
+ * @param evt the <tt>LocalUserChatRoomPresenceChangeEvent</tt> that
+ * notified us
*/
- public void messageReceived(MessageReceivedEvent evt)
+ public void localUserPresenceChanged(
+ LocalUserChatRoomPresenceChangeEvent evt)
{
- try
- {
- // Fire notification
- String title = NotificationWiringActivator.getResources().getI18NString(
- "service.gui.MSG_RECEIVED",
- new String[]{evt.getSourceContact().getDisplayName()});
+ ChatRoom sourceChatRoom = evt.getChatRoom();
+ String eventType = evt.getEventType();
- fireChatNotification(
- evt.getSourceContact(),
- INCOMING_MESSAGE,
- title,
- evt.getSourceMessage().getContent());
+ if (LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_JOINED.equals(eventType))
+ {
+ sourceChatRoom.addMessageListener(this);
}
- catch(Throwable t)
+ else if (LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_LEFT.equals(eventType)
+ || LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_KICKED.equals(eventType)
+ || LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_DROPPED.equals(eventType))
{
- logger.error("Error notifying for message received", t);
+ sourceChatRoom.removeMessageListener(this);
}
}
/**
- * Fired when message is delivered.
- * @param evt the <tt>MessageDeliveredEvent</tt> containing
- * details on the delivered message
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void messageDelivered(MessageDeliveredEvent evt)
- {}
+ public void messageDelivered(AdHocChatRoomMessageDeliveredEvent ev) {}
/**
- * Fired when message deliver fail.
- * @param evt the <tt>MessageDeliveryFailedEvent</tt> containing
- * details on the failed message
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void messageDeliveryFailed(MessageDeliveryFailedEvent evt)
- {}
+ public void messageDelivered(ChatRoomMessageDeliveredEvent ev) {}
/**
- * When a request has been received we show a notification.
+ * {@inheritDoc}
*
- * @param event <tt>FileTransferRequestEvent</tt>
- * @see FileTransferListener#fileTransferRequestReceived(FileTransferRequestEvent)
+ * Not used
*/
- public void fileTransferRequestReceived(FileTransferRequestEvent event)
- {
- try
- {
- IncomingFileTransferRequest request = event.getRequest();
- Contact sourceContact = request.getSender();
-
- //Fire notification
- String title = NotificationWiringActivator.getResources().getI18NString(
- "service.gui.FILE_RECEIVING_FROM",
- new String[]{sourceContact.getDisplayName()});
-
- fireChatNotification(
- sourceContact,
- INCOMING_FILE,
- title,
- request.getFileName());
- }
- catch(Throwable t)
- {
- logger.error("Error notifying for file transfer req received", t);
- }
- }
+ public void messageDelivered(MessageDeliveredEvent ev) {}
/**
- * Nothing to do here, because we already know when a file transfer is
- * created.
- * @param event the <tt>FileTransferCreatedEvent</tt> that notified us
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void fileTransferCreated(FileTransferCreatedEvent event)
- {}
+ public void messageDeliveryFailed(
+ AdHocChatRoomMessageDeliveryFailedEvent ev) {}
/**
- * Called when a new <tt>IncomingFileTransferRequest</tt> has been rejected.
- * Nothing to do here, because we are the one who rejects the request.
+ * {@inheritDoc}
*
- * @param event the <tt>FileTransferRequestEvent</tt> containing the
- * received request which was rejected.
+ * Not used.
*/
- public void fileTransferRequestRejected(FileTransferRequestEvent event)
- {}
+ public void messageDeliveryFailed(ChatRoomMessageDeliveryFailedEvent ev) {}
/**
- * Called when an <tt>IncomingFileTransferRequest</tt> has been canceled
- * from the contact who sent it.
+ * {@inheritDoc}
*
- * @param event the <tt>FileTransferRequestEvent</tt> containing the
- * request which was canceled.
+ * Not used.
*/
- public void fileTransferRequestCanceled(FileTransferRequestEvent event)
- {}
+ public void messageDeliveryFailed(MessageDeliveryFailedEvent ev) {}
/**
- * Informs the user what is the typing state of his chat contacts.
- *
- * @param event the event containing details on the typing notification
+ * Implements the <tt>AdHocChatRoomMessageListener.messageReceived</tt>
+ * method.
+ * <br>
+ * @param evt the <tt>AdHocChatRoomMessageReceivedEvent</tt> that notified
+ * us
*/
- public void typingNotificationReceived(TypingNotificationEvent event)
+ public void messageReceived(AdHocChatRoomMessageReceivedEvent evt)
{
try
{
- Contact contact = event.getSourceContact();
+ AdHocChatRoom sourceChatRoom = evt.getSourceChatRoom();
+ Contact sourceParticipant = evt.getSourceChatRoomParticipant();
- // we don't care for proactive notifications, different than typing
- // sometimes after closing chat we can see someone is typing us
- // its just server sanding that the chat is inactive (STATE_STOPPED)
- if(event.getTypingState()
- != OperationSetTypingNotifications.STATE_TYPING)
- return;
+ // Fire notification
+ boolean fireChatNotification;
- // check whether the current chat window shows the
- // chat we received a typing info for and in such case don't show
- // notifications
- UIService uiService = NotificationWiringActivator.getUIService();
+ String nickname = sourceChatRoom.getName();
+ String messageContent = evt.getMessage().getContent();
- if(uiService != null)
+ fireChatNotification =
+ (nickname == null)
+ || messageContent.toLowerCase().contains(
+ nickname.toLowerCase());
+
+ if (fireChatNotification)
{
- Chat chat = uiService.getCurrentChat();
- if(chat != null)
- {
- MetaContact metaContact = uiService.getChatContact(chat);
+ String title
+ = NotificationWiringActivator.getResources().getI18NString(
+ "service.gui.MSG_RECEIVED",
+ new String[] { sourceParticipant.getDisplayName() });
- if(metaContact != null && metaContact.containsContact(contact)
- && chat.isChatFocused())
- {
- return;
- }
- }
+ fireChatNotification(
+ sourceChatRoom,
+ INCOMING_MESSAGE,
+ title,
+ messageContent);
}
+ }
+ catch(Throwable t)
+ {
+ logger.error("Error notifying for adhoc message received", t);
+ }
+ }
- long currentTime = System.currentTimeMillis();
+ /**
+ * Implements the <tt>ChatRoomMessageListener.messageReceived</tt> method.
+ * <br>
+ * Obtains the corresponding <tt>ChatPanel</tt> and process the message
+ * there.
+ * @param evt the <tt>ChatRoomMessageReceivedEvent</tt> that notified us
+ * that a message has been received
+ */
+ public void messageReceived(ChatRoomMessageReceivedEvent evt)
+ {
+ try
+ {
+ ChatRoom sourceChatRoom = evt.getSourceChatRoom();
+ ChatRoomMember sourceMember = evt.getSourceChatRoomMember();
+
+ // Fire notification
+ boolean fireChatNotification;
+
+ String messageContent = evt.getMessage().getContent();
- if (this.proactiveTimer.size() > 0)
+ /*
+ * It is uncommon for IRC clients to display popup notifications for
+ * messages which are sent to public channels and which do not mention
+ * the nickname of the local user.
+ */
+ if (sourceChatRoom.isSystem()
+ || isPrivate(sourceChatRoom)
+ || (messageContent == null))
+ fireChatNotification = true;
+ else
{
- // first remove contacts that have been here longer than the
- // timeout to avoid memory leaks
- Iterator<Map.Entry<Contact, Long>> entries
- = this.proactiveTimer.entrySet().iterator();
- while (entries.hasNext())
- {
- Map.Entry<Contact, Long> entry = entries.next();
- Long lastNotificationDate = entry.getValue();
- if (lastNotificationDate.longValue() + 30000 < currentTime)
- {
- // The entry is outdated
- entries.remove();
- }
- }
+ String nickname = sourceChatRoom.getUserNickname();
- // Now, check if the contact is still in the map
- if (this.proactiveTimer.containsKey(contact))
- {
- // We already notified the others about this
- return;
- }
+ int atIx = -1;
+
+ if(nickname != null)
+ atIx = nickname.indexOf("@");
+
+ fireChatNotification =
+ (nickname == null)
+ || messageContent.toLowerCase().contains(
+ nickname.toLowerCase())
+ || ((atIx == -1)? false : messageContent.toLowerCase()
+ .contains(nickname.substring(0, atIx).toLowerCase()));
}
- this.proactiveTimer.put(contact, currentTime);
+ if (fireChatNotification)
+ {
+ String title
+ = NotificationWiringActivator.getResources().getI18NString(
+ "service.gui.MSG_RECEIVED",
+ new String[] { sourceMember.getName() });
- fireChatNotification(
- contact,
- PROACTIVE_NOTIFICATION,
- contact.getDisplayName(),
- NotificationWiringActivator.getResources()
- .getI18NString("service.gui.PROACTIVE_NOTIFICATION"));
+ fireChatNotification(
+ sourceChatRoom,
+ INCOMING_MESSAGE,
+ title,
+ messageContent);
+ }
}
catch(Throwable t)
{
- logger.error("Error notifying for typing evt received", t);
+ logger.error("Error notifying for chat room message received", t);
}
}
/**
- * Called to indicate that sending typing notification has failed.
- *
- * @param event a <tt>TypingNotificationEvent</tt> containing the sender
- * of the notification and its type.
- */
- public void typingNotificationDeliveryFailed(TypingNotificationEvent event)
- {}
-
- /**
- * Implements CallListener.incomingCallReceived. When a call is received
- * plays the ring phone sound to the user and gathers caller information
- * that may be used by a user-specified command (incomingCall event trigger).
- * @param event the <tt>CallEvent</tt>
+ * Fired on new messages.
+ * @param evt the <tt>MessageReceivedEvent</tt> containing
+ * details on the received message
*/
- public void incomingCallReceived(CallEvent event)
+ public void messageReceived(MessageReceivedEvent evt)
{
try
{
- Call call = event.getSourceCall();
- CallPeer firstPeer = call.getCallPeers().next();
- String peerName = firstPeer.getDisplayName();
-
- Map<String,String> peerInfo = new HashMap<String, String>();
- peerInfo.put("caller.uri", firstPeer.getURI());
- peerInfo.put("caller.address", firstPeer.getAddress());
- peerInfo.put("caller.name", firstPeer.getDisplayName());
- peerInfo.put("caller.id", firstPeer.getPeerID());
-
- callNotifications.put(event.getSourceCall(),
- fireNotification(
- INCOMING_CALL,
- "",
- NotificationWiringActivator.getResources()
- .getI18NString("service.gui.INCOMING_CALL",
- new String[]{peerName}),
- peerInfo));
-
- call.addCallChangeListener(this);
+ // Fire notification
+ String title = NotificationWiringActivator.getResources().getI18NString(
+ "service.gui.MSG_RECEIVED",
+ new String[]{evt.getSourceContact().getDisplayName()});
- if(call.getCallPeers().hasNext())
- {
- CallPeer peer = call.getCallPeers().next();
- peer.addCallPeerListener(this);
- peer.addCallPeerSecurityListener(this);
- peer.addCallPeerConferenceListener(this);
- }
+ fireChatNotification(
+ evt.getSourceContact(),
+ INCOMING_MESSAGE,
+ title,
+ evt.getSourceMessage().getContent());
}
catch(Throwable t)
{
- logger.error("Error notifying for incoming call received", t);
+ logger.error("Error notifying for message received", t);
}
}
@@ -1077,87 +1225,64 @@ public class NotificationManager
}
/**
- * Implements CallListener.callEnded. Stops sounds that are playing at
- * the moment if there're any.
- * @param event the <tt>CallEvent</tt>
- */
- public void callEnded(CallEvent event)
- {
- try
- {
- // Stop all telephony related sounds.
-// stopAllTelephonySounds();
- stopSound(callNotifications.get(event.getSourceCall()));
-
- // Play the hangup sound.
- fireNotification(HANG_UP);
- }
- catch(Throwable t)
- {
- logger.error("Error notifying for call ended", t);
- }
- }
-
- /**
- * Implements the <tt>CallChangeListener.callPeerAdded</tt> method.
- * @param evt the <tt>CallPeerEvent</tt> that notifies us for the change
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void callPeerAdded(CallPeerEvent evt)
- {
- CallPeer peer = evt.getSourceCallPeer();
-
- if(peer == null)
- return;
-
- peer.addCallPeerListener(this);
- peer.addCallPeerSecurityListener(this);
- peer.addCallPeerConferenceListener(this);
- }
+ public void peerAddressChanged(CallPeerChangeEvent ev) {}
/**
- * Implements the <tt>CallChangeListener.callPeerRemoved</tt> method.
- * @param evt the <tt>CallPeerEvent</tt> that has been triggered
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void callPeerRemoved(CallPeerEvent evt)
- {
- CallPeer peer = evt.getSourceCallPeer();
-
- if(peer == null)
- return;
-
- peer.removeCallPeerListener(this);
- peer.removeCallPeerSecurityListener(this);
- peer.addCallPeerConferenceListener(this);
- }
+ public void peerDisplayNameChanged(CallPeerChangeEvent ev) {}
/**
- * Call state changed.
- * @param evt the <tt>CallChangeEvent</tt> instance containing the source
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void callStateChanged(CallChangeEvent evt)
- {
- }
+ public void peerImageChanged(CallPeerChangeEvent ev) {}
/**
* Fired when peer's state is changed
*
- * @param evt fired CallPeerEvent
+ * @param ev fired CallPeerEvent
*/
- public void peerStateChanged(CallPeerChangeEvent evt)
+ public void peerStateChanged(CallPeerChangeEvent ev)
{
try
{
- CallPeer sourcePeer = evt.getSourceCallPeer();
- Call call = sourcePeer.getCall();
- CallPeerState newState = (CallPeerState) evt.getNewValue();
- CallPeerState oldState = (CallPeerState) evt.getOldValue();
+ final CallPeer peer = ev.getSourceCallPeer();
+ Call call = peer.getCall();
+ CallPeerState newState = (CallPeerState) ev.getNewValue();
+ CallPeerState oldState = (CallPeerState) ev.getOldValue();
// Play the dialing audio when in connecting and initiating call state.
// Stop the dialing audio when we enter any other state.
- if (newState == CallPeerState.INITIATING_CALL
- || newState == CallPeerState.CONNECTING)
+ if ((newState == CallPeerState.INITIATING_CALL)
+ || (newState == CallPeerState.CONNECTING))
{
- callNotifications.put(call, fireNotification(DIALING));
+ NotificationData notification
+ = fireNotification(
+ DIALING,
+ new Callable<Boolean>()
+ {
+ public Boolean call()
+ {
+ CallPeerState state = peer.getState();
+
+ return
+ CallPeerState.INITIATING_CALL.equals(
+ state)
+ || CallPeerState.CONNECTING.equals(
+ state);
+ }
+ });
+
+ if (notification != null)
+ callNotifications.put(call, notification);
}
else
{
@@ -1170,20 +1295,48 @@ public class NotificationManager
//need to fire a notification here.
&& oldState != CallPeerState.CONNECTING_WITH_EARLY_MEDIA)
{
- callNotifications.put(call, fireNotification(OUTGOING_CALL));
+ NotificationData notification
+ = fireNotification(
+ OUTGOING_CALL,
+ new Callable<Boolean>()
+ {
+ public Boolean call()
+ {
+ return
+ CallPeerState.ALERTING_REMOTE_SIDE
+ .equals(peer.getState());
+ }
+ });
+
+ if (notification != null)
+ callNotifications.put(call, notification);
}
else if (newState == CallPeerState.BUSY)
{
// We start the busy sound only if we're in a simple call.
if (!isConference(call))
{
- callNotifications.put(call, fireNotification(BUSY_CALL));
+ NotificationData notification
+ = fireNotification(
+ BUSY_CALL,
+ new Callable<Boolean>()
+ {
+ public Boolean call()
+ {
+ return
+ CallPeerState.BUSY.equals(
+ peer.getState());
+ }
+ });
+
+ if (notification != null)
+ callNotifications.put(call, notification);
}
}
- else if (newState == CallPeerState.DISCONNECTED
- || newState == CallPeerState.FAILED)
+ else if ((newState == CallPeerState.DISCONNECTED)
+ || (newState == CallPeerState.FAILED))
{
- callNotifications.put(call, fireNotification(HANG_UP));
+ fireNotification(HANG_UP);
}
}
catch(Throwable t)
@@ -1193,417 +1346,413 @@ public class NotificationManager
}
/**
- * Fired when peer's display name is changed
+ * {@inheritDoc}
*
- * @param evt fired CallPeerEvent
+ * Not used.
*/
- public void peerDisplayNameChanged(CallPeerChangeEvent evt)
- {}
+ public void peerTransportAddressChanged(CallPeerChangeEvent ev) {}
/**
- * Fired when peer's address is changed
- *
- * @param evt fired CallPeerEvent
- */
- public void peerAddressChanged(CallPeerChangeEvent evt)
- {}
-
- /**
- * Fired when peer's transport is changed
- *
- * @param evt fired CallPeerEvent
- */
- public void peerTransportAddressChanged(CallPeerChangeEvent evt)
- {}
-
- /**
- * Fired when peer's image is changed
+ * Notifies that a specific <tt>Recorder</tt> has
+ * stopped recording the media associated with it.
*
- * @param evt fired CallPeerEvent
- */
- public void peerImageChanged(CallPeerChangeEvent evt)
- {}
-
- /**
- * When a <tt>securityOnEvent</tt> is received.
- * @param evt the event we received
+ * @param recorder the <tt>Recorder</tt> which has stopped recording its
+ * associated media
*/
- public void securityOn(CallPeerSecurityOnEvent evt)
+ public void recorderStopped(Recorder recorder)
{
try
{
- CallPeer peer = (CallPeer) evt.getSource();
+ ResourceManagementService resources
+ = NotificationWiringActivator.getResources();
- if((evt.getSecurityController().requiresSecureSignalingTransport()
- && peer.getProtocolProvider().isSignalingTransportSecure())
- || !evt.getSecurityController().requiresSecureSignalingTransport())
- {
- fireNotification(CALL_SECURITY_ON);
- }
+ fireNotification(
+ CALL_SAVED,
+ resources.getI18NString(
+ "plugin.callrecordingconfig.CALL_SAVED"),
+ resources.getI18NString(
+ "plugin.callrecordingconfig.CALL_SAVED_TO",
+ new String[] { recorder.getFilename() }));
}
catch(Throwable t)
{
- logger.error("Error for notify for security event", t);
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
+ {
+ logger.error(
+ "An error occurred while trying to notify that"
+ + " the recording of a call has stopped.",
+ t);
+ }
}
}
/**
- * Indicates the new state through the security indicator components.
- * @param securityOffEvent the event we received
+ * Register all default notifications.
*/
- public void securityOff(CallPeerSecurityOffEvent securityOffEvent)
- {}
+ private void registerDefaultNotifications()
+ {
+ NotificationService notificationService
+ = NotificationWiringActivator.getNotificationService();
- /**
- * The handler for the security event received. The security event
- * represents a timeout trying to establish a secure connection.
- * Most probably the other peer doesn't support it.
- *
- * @param securityTimeoutEvent
- * the security timeout event received
- */
- public void securityTimeout(
- CallPeerSecurityTimeoutEvent securityTimeoutEvent)
- {}
+ if(notificationService == null)
+ return;
- /**
- * The handler for the security event received. The security event
- * for starting establish a secure connection.
- *
- * @param securityNegotiationStartedEvent
- * the security started event received
- */
- public void securityNegotiationStarted(
- CallPeerSecurityNegotiationStartedEvent securityNegotiationStartedEvent)
- {}
+ // Register incoming message notifications.
+ notificationService.registerDefaultNotificationForEvent(
+ INCOMING_MESSAGE,
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null,
+ null);
- /**
- * Processes the received security message.
- * @param event the event we received
- */
- public void securityMessageRecieved(CallPeerSecurityMessageEvent event)
- {
- try
- {
- int severity = event.getEventSeverity();
+ notificationService.registerDefaultNotificationForEvent(
+ INCOMING_MESSAGE,
+ new SoundNotificationAction(
+ SoundProperties.INCOMING_MESSAGE, -1, true, false, false));
- String messageTitle = null;
+ // Register incoming call notifications.
+ notificationService.registerDefaultNotificationForEvent(
+ INCOMING_CALL,
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null,
+ null);
- switch (severity)
- {
- // Don't play alert sound for Info or warning.
- case CallPeerSecurityMessageEvent.INFORMATION:
- {
- messageTitle = NotificationWiringActivator.getResources()
- .getI18NString("service.gui.SECURITY_INFO");
- break;
- }
- case CallPeerSecurityMessageEvent.WARNING:
- {
- messageTitle = NotificationWiringActivator.getResources()
- .getI18NString("service.gui.SECURITY_WARNING");
- break;
- }
- // Alert sound indicates: security cannot established
- case CallPeerSecurityMessageEvent.SEVERE:
- case CallPeerSecurityMessageEvent.ERROR:
- {
- messageTitle = NotificationWiringActivator.getResources()
- .getI18NString("service.gui.SECURITY_ERROR");
- fireNotification(CALL_SECURITY_ERROR);
- }
- }
+ SoundNotificationAction inCallSoundHandler
+ = new SoundNotificationAction(
+ SoundProperties.INCOMING_CALL, 2000, true, true, true);
- fireNotification(
+ notificationService.registerDefaultNotificationForEvent(
+ INCOMING_CALL,
+ inCallSoundHandler);
+
+ // Register outgoing call notifications.
+ SoundNotificationAction outCallSoundHandler
+ = new SoundNotificationAction(
+ SoundProperties.OUTGOING_CALL, 3000, false, true, false);
+
+ notificationService.registerDefaultNotificationForEvent(
+ OUTGOING_CALL,
+ outCallSoundHandler);
+
+ // Register busy call notifications.
+ notificationService.registerDefaultNotificationForEvent(
+ BUSY_CALL,
+ new SoundNotificationAction(
+ SoundProperties.BUSY,
+ 1,
+ false, true, false));
+
+ // Register dial notifications.
+ SoundNotificationAction dialSoundHandler
+ = new SoundNotificationAction(
+ SoundProperties.DIALING, -1, false, true, false);
+
+ notificationService.registerDefaultNotificationForEvent(
+ DIALING,
+ dialSoundHandler);
+
+ // Register the hangup sound notification.
+ notificationService.registerDefaultNotificationForEvent(
+ HANG_UP,
+ new SoundNotificationAction(
+ SoundProperties.HANG_UP,
+ -1,
+ false, true, false));
+
+ // Register proactive notifications.
+ notificationService.registerDefaultNotificationForEvent(
+ PROACTIVE_NOTIFICATION,
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null,
+ null);
+
+ // Register warning message notifications.
+ notificationService.registerDefaultNotificationForEvent(
SECURITY_MESSAGE,
- messageTitle,
- event.getI18nMessage());
- }
- catch(Throwable t)
- {
- logger.error("Error notifying for security message received", t);
- }
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null,
+ null);
+
+ // Register sound notification for security state on during a call.
+ notificationService.registerDefaultNotificationForEvent(
+ CALL_SECURITY_ON,
+ new SoundNotificationAction(
+ SoundProperties.CALL_SECURITY_ON, -1,
+ false, true, false));
+
+ // Register sound notification for security state off during a call.
+ notificationService.registerDefaultNotificationForEvent(
+ CALL_SECURITY_ERROR,
+ new SoundNotificationAction(
+ SoundProperties.CALL_SECURITY_ERROR, -1,
+ false, true, false));
+
+ // Register sound notification for incoming files.
+ notificationService.registerDefaultNotificationForEvent(
+ INCOMING_FILE,
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null,
+ null);
+
+ notificationService.registerDefaultNotificationForEvent(
+ INCOMING_FILE,
+ new SoundNotificationAction(
+ SoundProperties.INCOMING_FILE, -1,
+ true, false, false));
+
+ // Register notification for saved calls.
+ notificationService.registerDefaultNotificationForEvent(
+ CALL_SAVED,
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null,
+ null);
}
/**
- * Implements the <tt>ChatRoomMessageListener.messageReceived</tt> method.
- * <br>
- * Obtains the corresponding <tt>ChatPanel</tt> and process the message
- * there.
- * @param evt the <tt>ChatRoomMessageReceivedEvent</tt> that notified us
- * that a message has been received
+ * Processes the received security message.
+ * @param ev the event we received
*/
- public void messageReceived(ChatRoomMessageReceivedEvent evt)
+ public void securityMessageRecieved(CallPeerSecurityMessageEvent ev)
{
try
{
- ChatRoom sourceChatRoom = evt.getSourceChatRoom();
- ChatRoomMember sourceMember = evt.getSourceChatRoomMember();
-
- // Fire notification
- boolean fireChatNotification;
-
- String messageContent = evt.getMessage().getContent();
+ String messageTitleKey;
- /*
- * It is uncommon for IRC clients to display popup notifications for
- * messages which are sent to public channels and which do not mention
- * the nickname of the local user.
- */
- if (sourceChatRoom.isSystem()
- || isPrivate(sourceChatRoom)
- || (messageContent == null))
- fireChatNotification = true;
- else
+ switch (ev.getEventSeverity())
{
- String nickname = sourceChatRoom.getUserNickname();
+ // Don't play alert sound for Info or warning.
+ case CallPeerSecurityMessageEvent.INFORMATION:
+ messageTitleKey = "service.gui.SECURITY_INFO";
+ break;
- int atIx = -1;
+ case CallPeerSecurityMessageEvent.WARNING:
+ messageTitleKey = "service.gui.SECURITY_WARNING";
+ break;
- if(nickname != null)
- atIx = nickname.indexOf("@");
+ // Security cannot be established! Play an alert sound.
+ case CallPeerSecurityMessageEvent.SEVERE:
+ case CallPeerSecurityMessageEvent.ERROR:
+ messageTitleKey = "service.gui.SECURITY_ERROR";
+ fireNotification(CALL_SECURITY_ERROR);
+ break;
- fireChatNotification =
- (nickname == null)
- || messageContent.toLowerCase().contains(
- nickname.toLowerCase())
- || ((atIx == -1)? false : messageContent.toLowerCase()
- .contains(nickname.substring(0, atIx).toLowerCase()));
+ default:
+ /*
+ * Whatever other severity there is or will be, we do not how to
+ * react to it yet.
+ */
+ messageTitleKey = null;
}
- if (fireChatNotification)
+ if (messageTitleKey != null)
{
- String title
- = NotificationWiringActivator.getResources().getI18NString(
- "service.gui.MSG_RECEIVED",
- new String[] { sourceMember.getName() });
-
- fireChatNotification(
- sourceChatRoom,
- INCOMING_MESSAGE,
- title,
- messageContent);
+ fireNotification(
+ SECURITY_MESSAGE,
+ NotificationWiringActivator.getResources()
+ .getI18NString(messageTitleKey),
+ ev.getI18nMessage());
}
}
catch(Throwable t)
{
- logger.error("Error notifying for chat room message received", t);
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
+ {
+ logger.error(
+ "An error occurred while trying to notify"
+ + " about a security message",
+ t);
+ }
}
}
/**
- * Implements the <tt>ChatRoomMessageListener.messageDelivered</tt> method.
- * <br>
- * @param evt the <tt>ChatRoomMessageDeliveredEvent</tt> that notified us
- * that the message was delivered to its destination
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void messageDelivered(ChatRoomMessageDeliveredEvent evt)
- {}
+ public void securityNegotiationStarted(
+ CallPeerSecurityNegotiationStartedEvent ev) {}
/**
- * Implements the <tt>ChatRoomMessageListener.messageDeliveryFailed</tt>
- * method.
- * <br>
- * @param evt the <tt>ChatRoomMessageDeliveryFailedEvent</tt> that notified
- * us of a delivery failure
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void messageDeliveryFailed(ChatRoomMessageDeliveryFailedEvent evt)
- {}
+ public void securityOff(CallPeerSecurityOffEvent ev) {}
/**
- * Implements the
- * <tt>LocalUserChatRoomPresenceListener.localUserPresenceChanged</tt>
- * method.
- * @param evt the <tt>LocalUserChatRoomPresenceChangeEvent</tt> that
- * notified us
+ * When a <tt>securityOnEvent</tt> is received.
+ * @param ev the event we received
*/
- public void localUserPresenceChanged(
- LocalUserChatRoomPresenceChangeEvent evt)
+ public void securityOn(CallPeerSecurityOnEvent ev)
{
- ChatRoom sourceChatRoom = evt.getChatRoom();
- String eventType = evt.getEventType();
-
- if (LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_JOINED.equals(eventType))
+ try
{
- sourceChatRoom.addMessageListener(this);
+ SrtpControl securityController = ev.getSecurityController();
+ CallPeer peer = (CallPeer) ev.getSource();
+
+ if(!securityController.requiresSecureSignalingTransport()
+ || peer.getProtocolProvider().isSignalingTransportSecure())
+ {
+ fireNotification(CALL_SECURITY_ON);
+ }
}
- else if (LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_LEFT.equals(eventType)
- || LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_KICKED.equals(eventType)
- || LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_DROPPED.equals(eventType))
+ catch(Throwable t)
{
- sourceChatRoom.removeMessageListener(this);
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
+ {
+ logger.error(
+ "An error occurred while trying to notify"
+ + " about a security-related event",
+ t);
+ }
}
}
/**
- * Implements the
- * <tt>LocalUserAdHocChatRoomPresenceListener.localUserPresenceChanged</tt>
- * method
+ * {@inheritDoc}
*
- * @param evt the <tt>LocalUserAdHocChatRoomPresenceChangeEvent</tt> that
- * notified us of a presence change
+ * Not used.
*/
- public void localUserAdHocPresenceChanged(
- LocalUserAdHocChatRoomPresenceChangeEvent evt)
- {
- String eventType = evt.getEventType();
-
- if (LocalUserAdHocChatRoomPresenceChangeEvent
- .LOCAL_USER_JOINED.equals(eventType))
- {
- evt.getAdHocChatRoom().addMessageListener(this);
- }
- else if (LocalUserAdHocChatRoomPresenceChangeEvent
- .LOCAL_USER_LEFT.equals(eventType)
- || LocalUserAdHocChatRoomPresenceChangeEvent
- .LOCAL_USER_DROPPED.equals(eventType))
- {
- evt.getAdHocChatRoom().removeMessageListener(this);
- }
- }
+ public void securityTimeout(CallPeerSecurityTimeoutEvent ev) {}
/**
- * Implements the <tt>AdHocChatRoomMessageListener.messageReceived</tt>
- * method.
- * <br>
- * @param evt the <tt>AdHocChatRoomMessageReceivedEvent</tt> that notified
- * us
+ * Implements the <tt>ServiceListener</tt> method. Verifies whether the
+ * passed event concerns a <tt>ProtocolProviderService</tt> and adds the
+ * corresponding listeners.
+ *
+ * @param event The <tt>ServiceEvent</tt> object.
*/
- public void messageReceived(AdHocChatRoomMessageReceivedEvent evt)
+ public void serviceChanged(ServiceEvent event)
{
- try
- {
- AdHocChatRoom sourceChatRoom = evt.getSourceChatRoom();
- Contact sourceParticipant = evt.getSourceChatRoomParticipant();
-
- // Fire notification
- boolean fireChatNotification;
+ ServiceReference serviceRef = event.getServiceReference();
- String nickname = sourceChatRoom.getName();
- String messageContent = evt.getMessage().getContent();
+ // if the event is caused by a bundle being stopped, we don't want to
+ // know
+ if (serviceRef.getBundle().getState() == Bundle.STOPPING)
+ return;
- fireChatNotification =
- (nickname == null)
- || messageContent.toLowerCase().contains(
- nickname.toLowerCase());
+ Object service
+ = NotificationWiringActivator.bundleContext.getService(serviceRef);
- if (fireChatNotification)
+ // we don't care if the source service is not a protocol provider
+ if (service instanceof ProtocolProviderService)
+ {
+ switch (event.getType())
{
- String title
- = NotificationWiringActivator.getResources().getI18NString(
- "service.gui.MSG_RECEIVED",
- new String[] { sourceParticipant.getDisplayName() });
-
- fireChatNotification(
- sourceChatRoom,
- INCOMING_MESSAGE,
- title,
- messageContent);
+ case ServiceEvent.REGISTERED:
+ handleProviderAdded((ProtocolProviderService) service);
+ break;
+ case ServiceEvent.UNREGISTERING:
+ handleProviderRemoved((ProtocolProviderService) service);
+ break;
}
}
- catch(Throwable t)
- {
- logger.error("Error notifying for adhoc message received", t);
- }
}
/**
- * Implements the <tt>ChatRoomMessageListener.messageDelivered</tt> method.
- * <br>
- * @param evt the <tt>ChatRoomMessageDeliveredEvent</tt> that notified us
- * that the message was delivered to its destination
- */
- public void messageDelivered(AdHocChatRoomMessageDeliveredEvent evt)
- {}
-
- /**
- * Implements <tt>AdHocChatRoomMessageListener.messageDeliveryFailed</tt>
- * method.
- * <br>
- * In the conversation area shows an error message, explaining the problem.
- * @param evt the <tt>AdHocChatRoomMessageDeliveryFailedEvent</tt> that
- * notified us
- */
- public void messageDeliveryFailed(AdHocChatRoomMessageDeliveryFailedEvent evt)
- {}
-
- /**
- * Call peer has changed.
- * @param conferenceEvent
- * a <tt>CallPeerConferenceEvent</tt> with ID
- * <tt>CallPeerConferenceEvent#CONFERENCE_FOCUS_CHANGED</tt>
+ * {@inheritDoc}
+ *
+ * Not used.
*/
- public void conferenceFocusChanged(CallPeerConferenceEvent conferenceEvent)
- {}
+ public void typingNotificationDeliveryFailed(TypingNotificationEvent ev) {}
/**
- * Indicates that the given conference member has been added to the given
- * peer.
+ * Informs the user what is the typing state of his chat contacts.
*
- * @param conferenceEvent the event
+ * @param ev the event containing details on the typing notification
*/
- public void conferenceMemberAdded(CallPeerConferenceEvent conferenceEvent)
+ public void typingNotificationReceived(TypingNotificationEvent ev)
{
try
{
- CallPeer peer
- = conferenceEvent
- .getConferenceMember()
- .getConferenceFocusCallPeer();
+ Contact contact = ev.getSourceContact();
- if(peer.getConferenceMemberCount() > 0)
+ // we don't care for proactive notifications, different than typing
+ // sometimes after closing chat we can see someone is typing us
+ // its just server sanding that the chat is inactive (STATE_STOPPED)
+ if(ev.getTypingState()
+ != OperationSetTypingNotifications.STATE_TYPING)
{
- CallPeerSecurityStatusEvent securityEvent
- = peer.getCurrentSecuritySettings();
+ return;
+ }
- if (securityEvent instanceof CallPeerSecurityOnEvent)
- fireNotification(CALL_SECURITY_ON);
+ // check whether the current chat window shows the
+ // chat we received a typing info for and in such case don't show
+ // notifications
+ UIService uiService = NotificationWiringActivator.getUIService();
+
+ if(uiService != null)
+ {
+ Chat chat = uiService.getCurrentChat();
+
+ if(chat != null)
+ {
+ MetaContact metaContact = uiService.getChatContact(chat);
+
+ if((metaContact != null)
+ && metaContact.containsContact(contact)
+ && chat.isChatFocused())
+ {
+ return;
+ }
+ }
}
- }
- catch(Throwable t)
- {
- if (t instanceof ThreadDeath)
- throw (ThreadDeath) t;
- else
- logger.error("Error notifying for secured call member", t);
- }
- }
- /**
- * Indicates that the given conference member has been removed from the
- * given peer.
- *
- * @param conferenceEvent the event
- */
- public void conferenceMemberRemoved(CallPeerConferenceEvent conferenceEvent)
- {}
+ long currentTime = System.currentTimeMillis();
- /**
- * Notifies that a specific <tt>Recorder</tt> has
- * stopped recording the media associated with it.
- *
- * @param recorder the <tt>Recorder</tt> which has stopped recording its
- * associated media
- */
- public void recorderStopped(Recorder recorder)
- {
- try
- {
- fireNotification(
- CALL_SAVED,
- NotificationWiringActivator.getResources().getI18NString(
- "plugin.callrecordingconfig.CALL_SAVED"),
+ if (proactiveTimer.size() > 0)
+ {
+ // first remove contacts that have been here longer than the
+ // timeout to avoid memory leaks
+ Iterator<Map.Entry<Contact, Long>> entries
+ = proactiveTimer.entrySet().iterator();
+
+ while (entries.hasNext())
+ {
+ Map.Entry<Contact, Long> entry = entries.next();
+ Long lastNotificationDate = entry.getValue();
+
+ if (lastNotificationDate.longValue() + 30000 < currentTime)
+ {
+ // The entry is outdated
+ entries.remove();
+ }
+ }
+
+ // Now, check if the contact is still in the map
+ if (proactiveTimer.containsKey(contact))
+ {
+ // We already notified the others about this
+ return;
+ }
+ }
+
+ proactiveTimer.put(contact, currentTime);
+
+ fireChatNotification(
+ contact,
+ PROACTIVE_NOTIFICATION,
+ contact.getDisplayName(),
NotificationWiringActivator.getResources().getI18NString(
- "plugin.callrecordingconfig.CALL_SAVED_TO",
- new String[] { recorder.getFilename() }));
+ "service.gui.PROACTIVE_NOTIFICATION"));
}
catch(Throwable t)
{
- logger.error("Error notifying for recorder stopped", t);
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
+ {
+ logger.error(
+ "An error occurred while handling"
+ + " a typing notification.",
+ t);
+ }
}
}
}
diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java
index b8983dd..17958d2 100644
--- a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java
+++ b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java
@@ -606,7 +606,6 @@ public class ReconnectPluginActivator
NETWORK_NOTIFICATIONS,
title,
getResources().getI18NString(i18nKey, params),
- null,
null);
}
diff --git a/src/net/java/sip/communicator/service/notification/CommandNotificationHandler.java b/src/net/java/sip/communicator/service/notification/CommandNotificationHandler.java
index 8540166..e59e73a 100644
--- a/src/net/java/sip/communicator/service/notification/CommandNotificationHandler.java
+++ b/src/net/java/sip/communicator/service/notification/CommandNotificationHandler.java
@@ -19,10 +19,12 @@ public interface CommandNotificationHandler
{
/**
* Executes the program pointed by the descriptor.
+ *
* @param action the action to act upon
* @param cmdargs arguments that are passed to the command line specified
* in the action
*/
- public void execute(CommandNotificationAction action,
- Map<String,String> cmdargs);
+ public void execute(
+ CommandNotificationAction action,
+ Map<String,String> cmdargs);
}
diff --git a/src/net/java/sip/communicator/service/notification/NotificationData.java b/src/net/java/sip/communicator/service/notification/NotificationData.java
index d88b6e6..fb88de0 100644
--- a/src/net/java/sip/communicator/service/notification/NotificationData.java
+++ b/src/net/java/sip/communicator/service/notification/NotificationData.java
@@ -16,34 +16,71 @@ import java.util.*;
*/
public class NotificationData
{
+ /**
+ * The name/key of the <tt>NotificationData</tt> extra which is provided to
+ * {@link CommandNotificationHandler#execute(CommandNotificationAction,
+ * Map)} i.e. a <tt>Map&lt;String,String&gt;</tt> which is known by the
+ * (argument) name <tt>cmdargs</tt>.
+ */
+ public static final String COMMAND_NOTIFICATION_HANDLER_CMDARGS_EXTRA
+ = "CommandNotificationHandler.cmdargs";
+
+ /**
+ * The name/key of the <tt>NotificationData</tt> extra which is provided to
+ * {@link PopupMessageNotificationHandler#popupMessage(
+ * PopupMessageNotificationAction, String, String, byte[], Object)} i.e. an
+ * <tt>Object</tt> which is known by the (argument) name <tt>tag</tt>.
+ */
+ public static final String POPUP_MESSAGE_HANDLER_TAG_EXTRA
+ = "PopupMessageNotificationHandler.tag";
+
+ /**
+ * The name/key of the <tt>NotificationData</tt> extra which is provided to
+ * {@link SoundNotificationHandler} i.e. a <tt>Callable&lt;Boolean&gt;</tt>
+ * which is known as the condition which determines whether looping sounds
+ * are to continue playing.
+ */
+ public static final String SOUND_NOTIFICATION_HANDLER_LOOP_CONDITION_EXTRA
+ = "SoundNotificationHandler.loopCondition";
+
private final String eventType;
- private final String title;
- private final String message;
- private final Map<String,String> extra;
+
+ /**
+ * The {@link NotificationHandler}-specific extras provided to this
+ * instance. The keys are among the <tt>XXX_EXTRA</tt> constants defined by
+ * the <tt>NotificationData</tt> class.
+ */
+ private final Map<String, Object> extras;
+
private final byte[] icon;
- private final Object tag;
+ private final String message;
+ private final String title;
/**
* Creates a new instance of this class.
*
* @param eventType the type of the event that we'd like to fire a
- * notification for.
+ * notification for.
* @param title the title of the given message
* @param message the message to use if and where appropriate (e.g. with
- * systray or log notification.)
- * @param extra additional data (such as caller information)
+ * systray or log notification.)
* @param icon the icon to show in the notification if and where appropriate
- * @param tag additional info to be used by the notification handler
+ * @param extras additional/extra {@link NotificationHandler}-specific data
+ * to be provided by the new instance to the various
+ * <tt>NotificationHandler</tt>s
*/
- NotificationData(String eventType, String title, String message,
- Map<String,String> extra, byte[] icon, Object tag)
+ NotificationData(
+ String eventType,
+ String title,
+ String message,
+ byte[] icon,
+ Map<String, Object> extras)
{
this.eventType = eventType;
this.title = title;
this.message = message;
- this.extra = extra;
this.icon = icon;
- this.tag = tag;
+ this.extras = extras;
}
/**
@@ -57,53 +94,61 @@ public class NotificationData
}
/**
- * Gets the title of the given message.
- *
- * @return the title
+ * Gets the {@link NotificationHandler}-specific extras provided to this
+ * instance.
+ *
+ * @return the <tt>NotificationHandler</tt>-specific extras provided to this
+ * instance. The keys are among the <tt>XXX_EXTRA</tt> constants defined by
+ * the <tt>NotificationData</tt> class
*/
- String getTitle()
+ Map<String, Object> getExtras()
{
- return title;
+ return Collections.unmodifiableMap(extras);
}
/**
- * Gets the message to use if and where appropriate (e.g. with systray or
- * log notification).
- *
- * @return the message
+ * Gets the {@link NotificationHandler}-specific extra provided to this
+ * instance associated with a specific key.
+ *
+ * @param key the key whose associated <tt>NotificationHandler</tt>-specific
+ * extra is to be returned. Well known keys are defined by the
+ * <tt>NotificationData</tt> class as the <tt>XXX_EXTRA</tt> constants.
+ * @return the <tt>NotificationHandler</tt>-specific extra provided to this
+ * instance associated with the specified <tt>key</tt>
*/
- String getMessage()
+ public Object getExtra(String key)
{
- return message;
+ return (extras == null) ? null : extras.get(key);
}
/**
- * Gets additional data (such as caller information).
+ * Gets the icon to show in the notification if and where appropriate.
*
- * @return the extra data
+ * @return the icon
*/
- public Map<String,String> getExtra()
+ byte[] getIcon()
{
- return extra;
+ return icon;
}
/**
- * Gets the icon to show in the notification if and where appropriate.
+ * Gets the message to use if and where appropriate (e.g. with systray or
+ * log notification).
*
- * @return the icon
+ * @return the message
*/
- byte[] getIcon()
+ String getMessage()
{
- return icon;
+ return message;
}
/**
- * Gets additional info to be used by the notification handler.
+ * Gets the title of the given message.
*
- * @return the tag
+ * @return the title
*/
- Object getTag()
+ String getTitle()
{
- return tag;
+ return title;
}
}
diff --git a/src/net/java/sip/communicator/service/notification/NotificationService.java b/src/net/java/sip/communicator/service/notification/NotificationService.java
index c0b61ea..5de9a31 100644
--- a/src/net/java/sip/communicator/service/notification/NotificationService.java
+++ b/src/net/java/sip/communicator/service/notification/NotificationService.java
@@ -235,6 +235,7 @@ public interface NotificationService
* <p>
* This method does nothing if the given <tt>eventType</tt> is not contained
* in the list of registered event types.
+ * </p>
*
* @param eventType the type of the event that we'd like to fire a
* notification for.
@@ -243,7 +244,6 @@ public interface NotificationService
* @param message the message to use if and where appropriate (e.g. with
* systray or log notification.)
* @param icon the icon to show in the notification if and where appropriate
- * @param tag additional info to be used by the notification handler
* @return An object referencing the notification. It may be used to stop a
* still running notification. Can be null if the eventType is
* unknown or the notification is not active.
@@ -251,8 +251,7 @@ public interface NotificationService
public NotificationData fireNotification( String eventType,
String messageTitle,
String message,
- byte[] icon,
- Object tag);
+ byte[] icon);
/**
* Fires all notifications registered for the specified <tt>eventType</tt>
@@ -268,19 +267,21 @@ public interface NotificationService
* (e.g. with systray)
* @param message the message to use if and where appropriate (e.g. with
* systray or log notification.)
- * @param extra the extra data to pass (especially for Command execution)
* @param icon the icon to show in the notification if and where appropriate
- * @param tag additional info to be used by the notification handler
+ * @param extras additional/extra {@link NotificationHandler}-specific data
+ * to be provided to the firing of the specified notification(s). The
+ * well-known keys are defined by the <tt>NotificationData</tt>
+ * <tt>XXX_EXTRA</tt> constants.
* @return An object referencing the notification. It may be used to stop a
* still running notification. Can be null if the eventType is
* unknown or the notification is not active.
*/
- public NotificationData fireNotification( String eventType,
- String messageTitle,
- String message,
- Map<String,String> extra,
- byte[] icon,
- Object tag);
+ public NotificationData fireNotification(
+ String eventType,
+ String messageTitle,
+ String message,
+ byte[] icon,
+ Map<String,Object> extras);
/**
* Fires all notifications registered for the specified <tt>eventType</tt>
diff --git a/src/net/java/sip/communicator/service/notification/NotificationServiceImpl.java b/src/net/java/sip/communicator/service/notification/NotificationServiceImpl.java
index 648b8bd..64a7369 100644
--- a/src/net/java/sip/communicator/service/notification/NotificationServiceImpl.java
+++ b/src/net/java/sip/communicator/service/notification/NotificationServiceImpl.java
@@ -33,20 +33,17 @@ import org.jitsi.service.configuration.*;
class NotificationServiceImpl
implements NotificationService
{
- private final Logger logger
- = Logger.getLogger(NotificationServiceImpl.class);
-
- private final ConfigurationService configService =
- NotificationServiceActivator.getConfigurationService();
-
private static final String NOTIFICATIONS_PREFIX
= "net.java.sip.communicator.impl.notifications";
/**
- * A set of all registered event notifications.
+ * A list of all registered <tt>NotificationChangeListener</tt>s.
*/
- private final Map<String, Notification> notifications
- = new HashMap<String, Notification>();
+ private final List<NotificationChangeListener> changeListeners
+ = new Vector<NotificationChangeListener>();
+
+ private final ConfigurationService configService =
+ NotificationServiceActivator.getConfigurationService();
/**
* A set of all registered event notifications.
@@ -60,11 +57,8 @@ class NotificationServiceImpl
private final Map<String, NotificationHandler> handlers
= new HashMap<String, NotificationHandler>();
- /**
- * A list of all registered <tt>NotificationChangeListener</tt>s.
- */
- private final List<NotificationChangeListener> changeListeners
- = new Vector<NotificationChangeListener>();
+ private final Logger logger
+ = Logger.getLogger(NotificationServiceImpl.class);
/**
* Queue to cache fired notifications before all handlers are registered.
@@ -73,6 +67,12 @@ class NotificationServiceImpl
= new LinkedList<NotificationData>();
/**
+ * A set of all registered event notifications.
+ */
+ private final Map<String, Notification> notifications
+ = new HashMap<String, Notification>();
+
+ /**
* Creates an instance of <tt>NotificationServiceImpl</tt> by loading all
* previously saved notifications.
*/
@@ -83,198 +83,31 @@ class NotificationServiceImpl
}
/**
- * Creates a new <tt>EventNotification</tt> or obtains the corresponding
- * existing one and registers a new action in it.
+ * Adds an object that executes the actual action of a notification action.
+ * If the same action type is added twice, the last added wins.
*
- * @param eventType the name of the event (as defined by the plugin that's
- * registering it) that we are setting an action for.
- * @param action the <tt>NotificationAction</tt> responsible for
- * handling the given <tt>actionType</tt>
+ * @param handler The handler that executes the action.
*/
- public void registerNotificationForEvent( String eventType,
- NotificationAction action)
+ public void addActionHandler(NotificationHandler handler)
{
- Notification notification = null;
-
- if(notifications.containsKey(eventType))
- notification = notifications.get(eventType);
- else
- {
- notification = new Notification(eventType);
- notifications.put(eventType, notification);
-
- this.fireNotificationEventTypeEvent(
- EVENT_TYPE_ADDED, eventType);
- }
-
- Object existingAction = notification.addAction(action);
+ if(handler == null)
+ throw new IllegalArgumentException("handler cannot be null");
- // We fire the appropriate event depending on whether this is an
- // already existing actionType or a new one.
- if (existingAction != null)
- {
- fireNotificationActionTypeEvent(
- ACTION_CHANGED,
- eventType,
- action);
- }
- else
+ synchronized(handlers)
{
- fireNotificationActionTypeEvent(
- ACTION_ADDED,
- eventType,
- action);
- }
-
- // Save the notification through the ConfigurationService.
- this.saveNotification(eventType,
- action,
- true,
- false);
- }
-
- /**
- * Creates a new <tt>EventNotification</tt> or obtains the corresponding
- * existing one and registers a new action in it.
- *
- * @param eventType the name of the event (as defined by the plugin that's
- * registering it) that we are setting an action for.
- * @param actionType the type of the action that is to be executed when the
- * specified event occurs (could be one of the ACTION_XXX fields).
- * @param actionDescriptor a String containing a description of the action
- * (a URI to the sound file for audio notifications or a command line for
- * exec action types) that should be executed when the action occurs.
- * @param defaultMessage the default message to use if no specific message
- * has been provided when firing the notification.
- */
- public void registerNotificationForEvent( String eventType,
- String actionType,
- String actionDescriptor,
- String defaultMessage)
- {
- if (logger.isDebugEnabled())
- logger.debug("Registering event " + eventType + "/" +
- actionType + "/" + actionDescriptor + "/" + defaultMessage);
+ handlers.put(handler.getActionType(), handler);
+ if((handlers.size() == NUM_ACTIONS) && (notificationCache != null))
+ {
+ for(NotificationData event : notificationCache)
+ fireNotification(event);
- if (actionType.equals(ACTION_SOUND))
- {
- Notification notification = defaultNotifications.get(eventType);
- SoundNotificationAction action =
- (SoundNotificationAction) notification.getAction(ACTION_SOUND);
- registerNotificationForEvent (
- eventType,
- new SoundNotificationAction(
- actionDescriptor,
- action.getLoopInterval()));
- }
- else if (actionType.equals(ACTION_LOG_MESSAGE))
- {
- registerNotificationForEvent (eventType,
- new LogMessageNotificationAction(
- LogMessageNotificationAction.INFO_LOG_TYPE));
- }
- else if (actionType.equals(ACTION_POPUP_MESSAGE))
- {
- registerNotificationForEvent (eventType,
- new PopupMessageNotificationAction(defaultMessage));
- }
- else if (actionType.equals(ACTION_COMMAND))
- {
- registerNotificationForEvent (eventType,
- new CommandNotificationAction(actionDescriptor));
+ notificationCache.clear();
+ notificationCache = null;
+ }
}
}
/**
- * Removes the <tt>EventNotification</tt> corresponding to the given
- * <tt>eventType</tt> from the table of registered event notifications.
- *
- * @param eventType the name of the event (as defined by the plugin that's
- * registering it) to be removed.
- */
- public void removeEventNotification(String eventType)
- {
- notifications.remove(eventType);
-
- this.fireNotificationEventTypeEvent(
- EVENT_TYPE_REMOVED, eventType);
- }
-
- /**
- * Removes the given actionType from the list of actions registered for the
- * given <tt>eventType</tt>.
- *
- * @param eventType the name of the event (as defined by the plugin that's
- * registering it) for which we'll remove the notification.
- * @param actionType the type of the action that is to be executed when the
- * specified event occurs (could be one of the ACTION_XXX fields).
- */
- public void removeEventNotificationAction( String eventType,
- String actionType)
- {
- Notification notification
- = notifications.get(eventType);
-
- if(notification == null)
- return;
-
- NotificationAction action = notification.getAction(actionType);
-
- if(action == null)
- return;
-
- notification.removeAction(actionType);
-
- saveNotification(
- eventType,
- action,
- false,
- false);
-
- fireNotificationActionTypeEvent(
- ACTION_REMOVED,
- eventType,
- action);
- }
-
- /**
- * Returns an iterator over a list of all events registered in this
- * notification service. Each line in the returned list consists of
- * a String, representing the name of the event (as defined by the plugin
- * that registered it).
- *
- * @return an iterator over a list of all events registered in this
- * notifications service
- */
- public Iterable<String> getRegisteredEvents()
- {
- return Collections.unmodifiableSet(
- notifications.keySet());
- }
-
- /**
- * Returns the notification action corresponding to the given
- * <tt>eventType</tt> and <tt>actionType</tt>.
- *
- * @param eventType the type of the event that we'd like to retrieve.
- * @param actionType the type of the action that we'd like to retrieve a
- * descriptor for.
- * @return the notification action of the action to be executed
- * when an event of the specified type has occurred.
- */
- public NotificationAction getEventNotificationAction(
- String eventType,
- String actionType)
- {
- Notification notification = notifications.get(eventType);
-
- if(notification == null)
- return null;
-
- return notification.getAction(actionType);
- }
-
- /**
* Adds the given <tt>listener</tt> to the list of change listeners.
*
* @param listener the listener that we'd like to register to listen for
@@ -290,80 +123,86 @@ class NotificationServiceImpl
}
/**
- * Removes the given <tt>listener</tt> from the list of change listeners.
- *
- * @param listener the listener that we'd like to remove
+ * Checking an action when it is edited (property .default=false).
+ * Checking for older versions of the property. If it is older one
+ * we migrate it to new configuration using the default values.
+ *
+ * @param eventType the event type.
+ * @param defaultAction the default action which values we will use.
*/
- public void removeNotificationChangeListener(
- NotificationChangeListener listener)
+ private void checkDefaultAgainstLoadedNotification
+ (String eventType, NotificationAction defaultAction)
{
- synchronized (changeListeners)
+ // checking for new sound action properties
+ if(defaultAction instanceof SoundNotificationAction)
{
- changeListeners.remove(listener);
- }
- }
+ SoundNotificationAction soundDefaultAction
+ = (SoundNotificationAction)defaultAction;
+ SoundNotificationAction soundAction = (SoundNotificationAction)
+ getEventNotificationAction(eventType, ACTION_SOUND);
- /**
- * Adds an object that executes the actual action of a notification action.
- * If the same action type is added twice, the last added wins.
- *
- * @param handler The handler that executes the action.
- */
- public void addActionHandler(NotificationHandler handler)
- {
- if(handler == null)
- throw new IllegalArgumentException("handler cannot be null");
+ boolean isSoundNotificationEnabledPropExist
+ = getNotificationActionProperty(
+ eventType,
+ defaultAction,
+ "isSoundNotificationEnabled") != null;
- synchronized(handlers)
- {
- handlers.put(handler.getActionType(), handler);
- if(handlers.size() == NUM_ACTIONS && notificationCache != null)
+ if(!isSoundNotificationEnabledPropExist)
{
- for(NotificationData event : notificationCache)
- fireNotification(event);
+ soundAction.setSoundNotificationEnabled(
+ soundDefaultAction.isSoundNotificationEnabled());
+ }
- notificationCache.clear();
- notificationCache = null;
+ boolean isSoundPlaybackEnabledPropExist
+ = getNotificationActionProperty(
+ eventType,
+ defaultAction,
+ "isSoundPlaybackEnabled") != null;
+
+ if(!isSoundPlaybackEnabledPropExist)
+ {
+ soundAction.setSoundPlaybackEnabled(
+ soundDefaultAction.isSoundPlaybackEnabled());
}
- }
- }
- /**
- * Removes an object that executes the actual action of notification action.
- * @param actionType The handler type to remove.
- */
- public void removeActionHandler(String actionType)
- {
- if(actionType == null)
- throw new IllegalArgumentException("actionType cannot be null");
+ boolean isSoundPCSpeakerEnabledPropExist
+ = getNotificationActionProperty(
+ eventType,
+ defaultAction,
+ "isSoundPCSpeakerEnabled") != null;
- synchronized(handlers)
- {
- handlers.remove(actionType);
- }
- }
+ if(!isSoundPCSpeakerEnabledPropExist)
+ {
+ soundAction.setSoundPCSpeakerEnabled(
+ soundDefaultAction.isSoundPCSpeakerEnabled());
+ }
- /**
- * Gets a list of handler for the specified action type.
- *
- * @param actionType the type for which the list of handlers should be
- * retrieved or <tt>null</tt> if all handlers shall be returned.
- */
- public Iterable<NotificationHandler> getActionHandlers(String actionType)
- {
- if (actionType != null)
- {
- NotificationHandler handler = handlers.get(actionType);
- Set<NotificationHandler> ret;
+ boolean fixDialingLoop = false;
- if (handler == null)
- ret = Collections.emptySet();
- else
- ret = Collections.singleton(handler);
- return ret;
+ // hack to fix wrong value:just check whether loop for outgoing call
+ // (dialing) has gone into config as 0, should be -1
+ if(eventType.equals("Dialing")
+ && soundAction.getLoopInterval() == 0)
+ {
+ soundAction.setLoopInterval(
+ soundDefaultAction.getLoopInterval());
+ fixDialingLoop = true;
+ }
+
+ if(!(isSoundNotificationEnabledPropExist
+ && isSoundPCSpeakerEnabledPropExist
+ && isSoundPlaybackEnabledPropExist)
+ || fixDialingLoop)
+ {
+ // this check is done only when the notification
+ // is edited and is not default
+ saveNotification(
+ eventType,
+ soundAction,
+ soundAction.isEnabled(),
+ false);
+ }
}
- else
- return handlers.values();
}
/**
@@ -373,71 +212,84 @@ class NotificationServiceImpl
private void fireNotification(NotificationData data)
{
Notification notification = notifications.get(data.getEventType());
- if(notification == null || !notification.isActive())
+
+ if((notification == null) || !notification.isActive())
return;
for(NotificationAction action : notification.getActions().values())
{
String actionType = action.getActionType();
- if(!action.isEnabled() || !handlers.containsKey(actionType))
+
+ if(!action.isEnabled())
continue;
NotificationHandler handler = handlers.get(actionType);
+
+ if (handler == null)
+ continue;
+
if (actionType.equals(ACTION_POPUP_MESSAGE))
{
- ((PopupMessageNotificationHandler) handler)
- .popupMessage((PopupMessageNotificationAction) action,
- data.getTitle(), data.getMessage(),
- data.getIcon(), data.getTag());
+ ((PopupMessageNotificationHandler) handler).popupMessage(
+ (PopupMessageNotificationAction) action,
+ data.getTitle(),
+ data.getMessage(),
+ data.getIcon(),
+ data.getExtra(
+ NotificationData
+ .POPUP_MESSAGE_HANDLER_TAG_EXTRA));
}
else if (actionType.equals(ACTION_LOG_MESSAGE))
{
- ((LogMessageNotificationHandler) handler)
- .logMessage((LogMessageNotificationAction) action,
+ ((LogMessageNotificationHandler) handler).logMessage(
+ (LogMessageNotificationAction) action,
data.getMessage());
}
else if (actionType.equals(ACTION_SOUND))
{
SoundNotificationAction soundNotificationAction
= (SoundNotificationAction) action;
+
if(soundNotificationAction.isSoundNotificationEnabled()
- || soundNotificationAction.isSoundPlaybackEnabled()
- || soundNotificationAction.isSoundPCSpeakerEnabled())
+ || soundNotificationAction.isSoundPlaybackEnabled()
+ || soundNotificationAction.isSoundPCSpeakerEnabled())
{
- ((SoundNotificationHandler) handler)
- .start((SoundNotificationAction) action, data);
+ ((SoundNotificationHandler) handler).start(
+ (SoundNotificationAction) action,
+ data);
}
}
else if (actionType.equals(ACTION_COMMAND))
{
- ((CommandNotificationHandler) handler)
- .execute(
- (CommandNotificationAction)action,
- data.getExtra());
+ @SuppressWarnings("unchecked")
+ Map<String, String> cmdargs
+ = (Map<String, String>)
+ data.getExtra(
+ NotificationData
+ .COMMAND_NOTIFICATION_HANDLER_CMDARGS_EXTRA);
+
+ ((CommandNotificationHandler) handler).execute(
+ (CommandNotificationAction) action,
+ cmdargs);
}
}
}
/**
- * Stops a notification if notification is continuous, like playing sounds
- * in loop. Do nothing if there are no such events currently processing.
- *
- * @param data the data that has been returned when firing the event..
+ * If there is a registered event notification of the given
+ * <tt>eventType</tt> and the event notification is currently activated, we
+ * go through the list of registered actions and execute them.
+ *
+ * @param eventType the type of the event that we'd like to fire a
+ * notification for.
+ *
+ * @return An object referencing the notification. It may be used to stop a
+ * still running notification. Can be null if the eventType is
+ * unknown or the notification is not active.
*/
- public void stopNotification(NotificationData data)
+ public NotificationData fireNotification(String eventType)
{
- Iterable<NotificationHandler> soundHandlers
- = getActionHandlers(NotificationAction.ACTION_SOUND);
-
- // There could be no sound action handler for this event type
- if (soundHandlers != null)
- {
- for (NotificationHandler handler : soundHandlers)
- {
- if (handler instanceof SoundNotificationHandler)
- ((SoundNotificationHandler) handler).stop(data);
- }
- }
+ return fireNotification(eventType, null, null, null);
}
/**
@@ -461,15 +313,9 @@ class NotificationServiceImpl
String eventType,
String title,
String message,
- byte[] icon,
- Object tag)
+ byte[] icon)
{
- return fireNotification(eventType,
- title,
- message,
- null,
- icon,
- tag);
+ return fireNotification(eventType, title, message, icon, null);
}
/**
@@ -482,28 +328,30 @@ class NotificationServiceImpl
* @param title the title of the given message
* @param message the message to use if and where appropriate (e.g. with
* systray or log notification.)
- * @param extra the extra data to pass (especially for Command execution)
* @param icon the icon to show in the notification if and where appropriate
- * @param tag additional info to be used by the notification handler
+ * @param extras additiona/extra {@link NotificationHandler}-specific data
+ * to be provided to the firing of the specified notification(s). The
+ * well-known keys are defined by the <tt>NotificationData</tt>
+ * <tt>XXX_EXTRA</tt> constants.
*
* @return An object referencing the notification. It may be used to stop a
* still running notification. Can be null if the eventType is
* unknown or the notification is not active.
*/
public NotificationData fireNotification(
- String eventType,
- String title,
- String message,
- Map<String,String> extra,
- byte[] icon,
- Object tag)
+ String eventType,
+ String title,
+ String message,
+ byte[] icon,
+ Map<String,Object> extras)
{
Notification notification = notifications.get(eventType);
- if(notification == null || !notification.isActive())
+
+ if((notification == null) || !notification.isActive())
return null;
- NotificationData data = new NotificationData(eventType, title,
- message, extra, icon, tag);
+ NotificationData data
+ = new NotificationData(eventType, title, message, icon, extras);
//cache the notification when the handlers are not yet ready
if (notificationCache != null)
@@ -515,35 +363,137 @@ class NotificationServiceImpl
}
/**
- * If there is a registered event notification of the given
- * <tt>eventType</tt> and the event notification is currently activated, we
- * go through the list of registered actions and execute them.
+ * Notifies all registered <tt>NotificationChangeListener</tt>s that a
+ * <tt>NotificationActionTypeEvent</tt> has occurred.
*
- * @param eventType the type of the event that we'd like to fire a
- * notification for.
+ * @param eventType the type of the event, which is one of ACTION_XXX
+ * constants declared in the <tt>NotificationActionTypeEvent</tt> class.
+ * @param sourceEventType the <tt>eventType</tt>, which is the parent of the
+ * action
+ * @param action the notification action
+ */
+ private void fireNotificationActionTypeEvent(
+ String eventType,
+ String sourceEventType,
+ NotificationAction action)
+ {
+ NotificationActionTypeEvent event
+ = new NotificationActionTypeEvent( this,
+ eventType,
+ sourceEventType,
+ action);
+
+
+ for(NotificationChangeListener listener : changeListeners)
+ {
+ if (eventType.equals(ACTION_ADDED))
+ {
+ listener.actionAdded(event);
+ }
+ else if (eventType.equals(ACTION_REMOVED))
+ {
+ listener.actionRemoved(event);
+ }
+ else if (eventType.equals(ACTION_CHANGED))
+ {
+ listener.actionChanged(event);
+ }
+ }
+ }
+
+ /**
+ * Notifies all registered <tt>NotificationChangeListener</tt>s that a
+ * <tt>NotificationEventTypeEvent</tt> has occurred.
*
- * @return An object referencing the notification. It may be used to stop a
- * still running notification. Can be null if the eventType is
- * unknown or the notification is not active.
+ * @param eventType the type of the event, which is one of EVENT_TYPE_XXX
+ * constants declared in the <tt>NotificationEventTypeEvent</tt> class.
+ * @param sourceEventType the <tt>eventType</tt>, for which this event is
+ * about
*/
- public NotificationData fireNotification(String eventType)
+ private void fireNotificationEventTypeEvent(String eventType,
+ String sourceEventType)
{
- return this.fireNotification(eventType, null, null, null, null, null);
+ if (logger.isDebugEnabled())
+ logger.debug("Dispatching NotificationEventType Change. Listeners="
+ + changeListeners.size()
+ + " evt=" + eventType);
+
+ NotificationEventTypeEvent event
+ = new NotificationEventTypeEvent(this, eventType, sourceEventType);
+
+ for (NotificationChangeListener listener : changeListeners)
+ {
+ if (eventType.equals(EVENT_TYPE_ADDED))
+ {
+ listener.eventTypeAdded(event);
+ }
+ else if (eventType.equals(EVENT_TYPE_REMOVED))
+ {
+ listener.eventTypeRemoved(event);
+ }
+ }
}
/**
- * Saves the event notification given by these parameters through the
- * <tt>ConfigurationService</tt>.
+ * Gets a list of handler for the specified action type.
*
- * @param eventType the name of the event
- * @param action the notification action to change
- * @param isActive is the event active
- * @param isDefault is it a default one
+ * @param actionType the type for which the list of handlers should be
+ * retrieved or <tt>null</tt> if all handlers shall be returned.
*/
- private void saveNotification( String eventType,
- NotificationAction action,
- boolean isActive,
- boolean isDefault)
+ public Iterable<NotificationHandler> getActionHandlers(String actionType)
+ {
+ if (actionType != null)
+ {
+ NotificationHandler handler = handlers.get(actionType);
+ Set<NotificationHandler> ret;
+
+ if (handler == null)
+ ret = Collections.emptySet();
+ else
+ ret = Collections.singleton(handler);
+ return ret;
+ }
+ else
+ return handlers.values();
+ }
+
+ /**
+ * Returns the notification action corresponding to the given
+ * <tt>eventType</tt> and <tt>actionType</tt>.
+ *
+ * @param eventType the type of the event that we'd like to retrieve.
+ * @param actionType the type of the action that we'd like to retrieve a
+ * descriptor for.
+ * @return the notification action of the action to be executed
+ * when an event of the specified type has occurred.
+ */
+ public NotificationAction getEventNotificationAction(
+ String eventType,
+ String actionType)
+ {
+ Notification notification = notifications.get(eventType);
+
+ return
+ (notification == null) ? null : notification.getAction(actionType);
+ }
+
+ /**
+ * Getting a notification property directly from configuration service.
+ * Used to check do we have an updated version of already saved/edited
+ * notification configurations. Detects old configurations.
+ *
+ * @param eventType the event type
+ * @param action the action which property to check.
+ * @param property the property name without the action prefix.
+ * @return the property value or null if missing.
+ * @throws IllegalArgumentException when the event ot action is not
+ * found.
+ */
+ private String getNotificationActionProperty(
+ String eventType,
+ NotificationAction action,
+ String property)
+ throws IllegalArgumentException
{
String eventTypeNodeName = null;
String actionTypeNodeName = null;
@@ -558,24 +508,11 @@ class NotificationServiceImpl
eventTypeNodeName = eventTypeRootPropName;
}
- // If we didn't find the given event type in the configuration we save
- // it here.
+ // If we didn't find the given event type in the configuration
+ // there is not need to further check
if(eventTypeNodeName == null)
{
- eventTypeNodeName = NOTIFICATIONS_PREFIX
- + ".eventType"
- + Long.toString(System.currentTimeMillis());
-
- configService.setProperty(eventTypeNodeName, eventType);
- }
-
- // if we set active/inactive for the whole event notification
- if(action == null)
- {
- configService.setProperty(
- eventTypeNodeName + ".active",
- Boolean.toString(isActive));
- return;
+ throw new IllegalArgumentException("Missing event type node");
}
// Go through contained actions.
@@ -591,81 +528,102 @@ class NotificationServiceImpl
actionTypeNodeName = actionTypeRootPropName;
}
- Map<String, Object> configProperties = new HashMap<String, Object>();
-
- // If we didn't find the given actionType in the configuration we save
- // it here.
+ // If we didn't find the given actionType in the configuration
+ // there is no need to further check
if(actionTypeNodeName == null)
- {
- actionTypeNodeName = actionPrefix
- + ".actionType"
- + Long.toString(System.currentTimeMillis());
+ throw new IllegalArgumentException("Missing action type node");
- configProperties.put(actionTypeNodeName, action.getActionType());
- }
+ return
+ (String)
+ configService.getProperty(actionTypeNodeName + "." + property);
+ }
- if(action instanceof SoundNotificationAction)
- {
- SoundNotificationAction soundAction
- = (SoundNotificationAction) action;
+ /**
+ * Returns an iterator over a list of all events registered in this
+ * notification service. Each line in the returned list consists of
+ * a String, representing the name of the event (as defined by the plugin
+ * that registered it).
+ *
+ * @return an iterator over a list of all events registered in this
+ * notifications service
+ */
+ public Iterable<String> getRegisteredEvents()
+ {
+ return Collections.unmodifiableSet(
+ notifications.keySet());
+ }
- configProperties.put(
- actionTypeNodeName + ".soundFileDescriptor",
- soundAction.getDescriptor());
+ /**
+ * Finds the <tt>EventNotification</tt> corresponding to the given
+ * <tt>eventType</tt> and returns its isActive status.
+ *
+ * @param eventType the name of the event (as defined by the plugin that's
+ * registered it) that we are checking.
+ * @return <code>true</code> if actions for the specified <tt>eventType</tt>
+ * are activated, <code>false</code> - otherwise. If the given
+ * <tt>eventType</tt> is not contained in the list of registered event
+ * types - returns <code>false</code>.
+ */
+ public boolean isActive(String eventType)
+ {
+ Notification eventNotification
+ = notifications.get(eventType);
- configProperties.put(
- actionTypeNodeName + ".loopInterval",
- soundAction.getLoopInterval());
+ if(eventNotification == null)
+ return false;
- configProperties.put(
- actionTypeNodeName + ".isSoundNotificationEnabled",
- soundAction.isSoundNotificationEnabled());
+ return eventNotification.isActive();
+ }
- configProperties.put(
- actionTypeNodeName + ".isSoundPlaybackEnabled",
- soundAction.isSoundPlaybackEnabled());
+ private boolean isDefault(String eventType, String actionType)
+ {
+ List<String> eventTypes = configService
+ .getPropertyNamesByPrefix(NOTIFICATIONS_PREFIX, true);
- configProperties.put(
- actionTypeNodeName + ".isSoundPCSpeakerEnabled",
- soundAction.isSoundPCSpeakerEnabled());
- }
- else if(action instanceof PopupMessageNotificationAction)
+ for (String eventTypeRootPropName : eventTypes)
{
- PopupMessageNotificationAction messageAction
- = (PopupMessageNotificationAction) action;
+ String eType
+ = configService.getString(eventTypeRootPropName);
- configProperties.put(
- actionTypeNodeName + ".defaultMessage",
- messageAction.getDefaultMessage());
- }
- else if(action instanceof LogMessageNotificationAction)
- {
- LogMessageNotificationAction logMessageAction
- = (LogMessageNotificationAction) action;
+ if(!eType.equals(eventType))
+ continue;
- configProperties.put(
- actionTypeNodeName + ".logType",
- logMessageAction.getLogType());
- }
- else if(action instanceof CommandNotificationAction)
- {
- CommandNotificationAction commandAction
- = (CommandNotificationAction) action;
+ List<String> actions = configService
+ .getPropertyNamesByPrefix(
+ eventTypeRootPropName + ".actions", true);
- configProperties.put(
- actionTypeNodeName + ".commandDescriptor",
- commandAction.getDescriptor());
- }
+ for (String actionPropName : actions)
+ {
+ String aType
+ = configService.getString(actionPropName);
- configProperties.put(
- actionTypeNodeName + ".enabled",
- Boolean.toString(isActive));
+ if(!aType.equals(actionType))
+ continue;
- configProperties.put(
- actionTypeNodeName + ".default",
- Boolean.toString(isDefault));
+ Object isDefaultdObj =
+ configService.getProperty(actionPropName + ".default");
- configService.setProperties(configProperties);
+ // if setting is missing we accept it is true
+ // this way we override old saved settings
+ if(isDefaultdObj == null)
+ return true;
+ else
+ return Boolean.parseBoolean((String)isDefaultdObj);
+ }
+ }
+ return true;
+ }
+
+ private boolean isEnabled(String configProperty)
+ {
+ Object isEnabledObj = configService.getProperty(configProperty);
+
+ // if setting is missing we accept it is true
+ // this way we not affect old saved settings
+ if(isEnabledObj == null)
+ return true;
+ else
+ return Boolean.parseBoolean((String)isEnabledObj);
}
/**
@@ -766,172 +724,6 @@ class NotificationServiceImpl
}
}
- private boolean isEnabled(String configProperty)
- {
- Object isEnabledObj = configService.getProperty(configProperty);
-
- // if setting is missing we accept it is true
- // this way we not affect old saved settings
- if(isEnabledObj == null)
- return true;
- else
- return Boolean.parseBoolean((String)isEnabledObj);
- }
-
- /**
- * Finds the <tt>EventNotification</tt> corresponding to the given
- * <tt>eventType</tt> and marks it as activated/deactivated.
- *
- * @param eventType the name of the event, which actions should be activated
- * /deactivated.
- * @param isActive indicates whether to activate or deactivate the actions
- * related to the specified <tt>eventType</tt>.
- */
- public void setActive(String eventType, boolean isActive)
- {
- Notification eventNotification
- = notifications.get(eventType);
-
- if(eventNotification == null)
- return;
-
- eventNotification.setActive(isActive);
- saveNotification(eventType, null, isActive, false);
- }
-
- /**
- * Finds the <tt>EventNotification</tt> corresponding to the given
- * <tt>eventType</tt> and returns its isActive status.
- *
- * @param eventType the name of the event (as defined by the plugin that's
- * registered it) that we are checking.
- * @return <code>true</code> if actions for the specified <tt>eventType</tt>
- * are activated, <code>false</code> - otherwise. If the given
- * <tt>eventType</tt> is not contained in the list of registered event
- * types - returns <code>false</code>.
- */
- public boolean isActive(String eventType)
- {
- Notification eventNotification
- = notifications.get(eventType);
-
- if(eventNotification == null)
- return false;
-
- return eventNotification.isActive();
- }
-
- /**
- * Notifies all registered <tt>NotificationChangeListener</tt>s that a
- * <tt>NotificationEventTypeEvent</tt> has occurred.
- *
- * @param eventType the type of the event, which is one of EVENT_TYPE_XXX
- * constants declared in the <tt>NotificationEventTypeEvent</tt> class.
- * @param sourceEventType the <tt>eventType</tt>, for which this event is
- * about
- */
- private void fireNotificationEventTypeEvent(String eventType,
- String sourceEventType)
- {
- if (logger.isDebugEnabled())
- logger.debug("Dispatching NotificationEventType Change. Listeners="
- + changeListeners.size()
- + " evt=" + eventType);
-
- NotificationEventTypeEvent event
- = new NotificationEventTypeEvent(this, eventType, sourceEventType);
-
- for (NotificationChangeListener listener : changeListeners)
- {
- if (eventType.equals(EVENT_TYPE_ADDED))
- {
- listener.eventTypeAdded(event);
- }
- else if (eventType.equals(EVENT_TYPE_REMOVED))
- {
- listener.eventTypeRemoved(event);
- }
- }
- }
-
- /**
- * Notifies all registered <tt>NotificationChangeListener</tt>s that a
- * <tt>NotificationActionTypeEvent</tt> has occurred.
- *
- * @param eventType the type of the event, which is one of ACTION_XXX
- * constants declared in the <tt>NotificationActionTypeEvent</tt> class.
- * @param sourceEventType the <tt>eventType</tt>, which is the parent of the
- * action
- * @param action the notification action
- */
- private void fireNotificationActionTypeEvent(
- String eventType,
- String sourceEventType,
- NotificationAction action)
- {
- NotificationActionTypeEvent event
- = new NotificationActionTypeEvent( this,
- eventType,
- sourceEventType,
- action);
-
-
- for(NotificationChangeListener listener : changeListeners)
- {
- if (eventType.equals(ACTION_ADDED))
- {
- listener.actionAdded(event);
- }
- else if (eventType.equals(ACTION_REMOVED))
- {
- listener.actionRemoved(event);
- }
- else if (eventType.equals(ACTION_CHANGED))
- {
- listener.actionChanged(event);
- }
- }
- }
-
- private boolean isDefault(String eventType, String actionType)
- {
- List<String> eventTypes = configService
- .getPropertyNamesByPrefix(NOTIFICATIONS_PREFIX, true);
-
- for (String eventTypeRootPropName : eventTypes)
- {
- String eType
- = configService.getString(eventTypeRootPropName);
-
- if(!eType.equals(eventType))
- continue;
-
- List<String> actions = configService
- .getPropertyNamesByPrefix(
- eventTypeRootPropName + ".actions", true);
-
- for (String actionPropName : actions)
- {
- String aType
- = configService.getString(actionPropName);
-
- if(!aType.equals(actionType))
- continue;
-
- Object isDefaultdObj =
- configService.getProperty(actionPropName + ".default");
-
- // if setting is missing we accept it is true
- // this way we override old saved settings
- if(isDefaultdObj == null)
- return true;
- else
- return Boolean.parseBoolean((String)isDefaultdObj);
- }
- }
- return true;
- }
-
/**
* Creates a new default <tt>EventNotification</tt> or obtains the
* corresponding existing one and registers a new action in it.
@@ -1114,105 +906,230 @@ class NotificationServiceImpl
}
/**
- * Checking an action when it is edited (property .default=false).
- * Checking for older versions of the property. If it is older one
- * we migrate it to new configuration using the default values.
- *
- * @param eventType the event type.
- * @param defaultAction the default action which values we will use.
+ * Creates a new <tt>EventNotification</tt> or obtains the corresponding
+ * existing one and registers a new action in it.
+ *
+ * @param eventType the name of the event (as defined by the plugin that's
+ * registering it) that we are setting an action for.
+ * @param action the <tt>NotificationAction</tt> responsible for
+ * handling the given <tt>actionType</tt>
*/
- private void checkDefaultAgainstLoadedNotification
- (String eventType, NotificationAction defaultAction)
+ public void registerNotificationForEvent( String eventType,
+ NotificationAction action)
{
- // checking for new sound action properties
- if(defaultAction instanceof SoundNotificationAction)
+ Notification notification = null;
+
+ if(notifications.containsKey(eventType))
+ notification = notifications.get(eventType);
+ else
{
- SoundNotificationAction soundDefaultAction
- = (SoundNotificationAction)defaultAction;
- SoundNotificationAction soundAction = (SoundNotificationAction)
- getEventNotificationAction(eventType, ACTION_SOUND);
+ notification = new Notification(eventType);
+ notifications.put(eventType, notification);
- boolean isSoundNotificationEnabledPropExist
- = getNotificationActionProperty(
- eventType,
- defaultAction,
- "isSoundNotificationEnabled") != null;
+ this.fireNotificationEventTypeEvent(
+ EVENT_TYPE_ADDED, eventType);
+ }
- if(!isSoundNotificationEnabledPropExist)
- {
- soundAction.setSoundNotificationEnabled(
- soundDefaultAction.isSoundNotificationEnabled());
- }
+ Object existingAction = notification.addAction(action);
- boolean isSoundPlaybackEnabledPropExist
- = getNotificationActionProperty(
- eventType,
- defaultAction,
- "isSoundPlaybackEnabled") != null;
+ // We fire the appropriate event depending on whether this is an
+ // already existing actionType or a new one.
+ if (existingAction != null)
+ {
+ fireNotificationActionTypeEvent(
+ ACTION_CHANGED,
+ eventType,
+ action);
+ }
+ else
+ {
+ fireNotificationActionTypeEvent(
+ ACTION_ADDED,
+ eventType,
+ action);
+ }
- if(!isSoundPlaybackEnabledPropExist)
- {
- soundAction.setSoundPlaybackEnabled(
- soundDefaultAction.isSoundPlaybackEnabled());
- }
+ // Save the notification through the ConfigurationService.
+ this.saveNotification(eventType,
+ action,
+ true,
+ false);
+ }
- boolean isSoundPCSpeakerEnabledPropExist
- = getNotificationActionProperty(
+ /**
+ * Creates a new <tt>EventNotification</tt> or obtains the corresponding
+ * existing one and registers a new action in it.
+ *
+ * @param eventType the name of the event (as defined by the plugin that's
+ * registering it) that we are setting an action for.
+ * @param actionType the type of the action that is to be executed when the
+ * specified event occurs (could be one of the ACTION_XXX fields).
+ * @param actionDescriptor a String containing a description of the action
+ * (a URI to the sound file for audio notifications or a command line for
+ * exec action types) that should be executed when the action occurs.
+ * @param defaultMessage the default message to use if no specific message
+ * has been provided when firing the notification.
+ */
+ public void registerNotificationForEvent( String eventType,
+ String actionType,
+ String actionDescriptor,
+ String defaultMessage)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Registering event " + eventType + "/" +
+ actionType + "/" + actionDescriptor + "/" + defaultMessage);
+
+ if (actionType.equals(ACTION_SOUND))
+ {
+ Notification notification = defaultNotifications.get(eventType);
+ SoundNotificationAction action =
+ (SoundNotificationAction) notification.getAction(ACTION_SOUND);
+ registerNotificationForEvent (
eventType,
- defaultAction,
- "isSoundPCSpeakerEnabled") != null;
+ new SoundNotificationAction(
+ actionDescriptor,
+ action.getLoopInterval()));
+ }
+ else if (actionType.equals(ACTION_LOG_MESSAGE))
+ {
+ registerNotificationForEvent (eventType,
+ new LogMessageNotificationAction(
+ LogMessageNotificationAction.INFO_LOG_TYPE));
+ }
+ else if (actionType.equals(ACTION_POPUP_MESSAGE))
+ {
+ registerNotificationForEvent (eventType,
+ new PopupMessageNotificationAction(defaultMessage));
+ }
+ else if (actionType.equals(ACTION_COMMAND))
+ {
+ registerNotificationForEvent (eventType,
+ new CommandNotificationAction(actionDescriptor));
+ }
+ }
- if(!isSoundPCSpeakerEnabledPropExist)
- {
- soundAction.setSoundPCSpeakerEnabled(
- soundDefaultAction.isSoundPCSpeakerEnabled());
- }
+ /**
+ * Removes an object that executes the actual action of notification action.
+ * @param actionType The handler type to remove.
+ */
+ public void removeActionHandler(String actionType)
+ {
+ if(actionType == null)
+ throw new IllegalArgumentException("actionType cannot be null");
- boolean fixDialingLoop = false;
+ synchronized(handlers)
+ {
+ handlers.remove(actionType);
+ }
+ }
- // hack to fix wrong value:just check whether loop for outgoing call
- // (dialing) has gone into config as 0, should be -1
- if(eventType.equals("Dialing")
- && soundAction.getLoopInterval() == 0)
- {
- soundAction.setLoopInterval(
- soundDefaultAction.getLoopInterval());
- fixDialingLoop = true;
- }
+ /**
+ * Removes the <tt>EventNotification</tt> corresponding to the given
+ * <tt>eventType</tt> from the table of registered event notifications.
+ *
+ * @param eventType the name of the event (as defined by the plugin that's
+ * registering it) to be removed.
+ */
+ public void removeEventNotification(String eventType)
+ {
+ notifications.remove(eventType);
+
+ this.fireNotificationEventTypeEvent(
+ EVENT_TYPE_REMOVED, eventType);
+ }
- if(!(isSoundNotificationEnabledPropExist
- && isSoundPCSpeakerEnabledPropExist
- && isSoundPlaybackEnabledPropExist)
- || fixDialingLoop)
- {
- // this check is done only when the notification
- // is edited and is not default
- saveNotification(
- eventType,
- soundAction,
- soundAction.isEnabled(),
- false);
- }
+ /**
+ * Removes the given actionType from the list of actions registered for the
+ * given <tt>eventType</tt>.
+ *
+ * @param eventType the name of the event (as defined by the plugin that's
+ * registering it) for which we'll remove the notification.
+ * @param actionType the type of the action that is to be executed when the
+ * specified event occurs (could be one of the ACTION_XXX fields).
+ */
+ public void removeEventNotificationAction( String eventType,
+ String actionType)
+ {
+ Notification notification
+ = notifications.get(eventType);
+
+ if(notification == null)
+ return;
+
+ NotificationAction action = notification.getAction(actionType);
+
+ if(action == null)
+ return;
+
+ notification.removeAction(actionType);
+
+ saveNotification(
+ eventType,
+ action,
+ false,
+ false);
+
+ fireNotificationActionTypeEvent(
+ ACTION_REMOVED,
+ eventType,
+ action);
+ }
+
+ /**
+ * Removes the given <tt>listener</tt> from the list of change listeners.
+ *
+ * @param listener the listener that we'd like to remove
+ */
+ public void removeNotificationChangeListener(
+ NotificationChangeListener listener)
+ {
+ synchronized (changeListeners)
+ {
+ changeListeners.remove(listener);
}
}
/**
- * Getting a notification property directly from configuration service.
- * Used to check do we have an updated version of already saved/edited
- * notification configurations. Detects old configurations.
- *
- * @param eventType the event type
- * @param action the action which property to check.
- * @param property the property name without the action prefix.
- * @return the property value or null if missing.
- * @throws IllegalArgumentException when the event ot action is not
- * found.
+ * Deletes all registered events and actions
+ * and registers and saves the default events as current.
*/
- private String getNotificationActionProperty(
- String eventType,
- NotificationAction action,
- String property)
- throws IllegalArgumentException
+ public void restoreDefaults()
+ {
+ for (String eventType : new Vector<String>(notifications.keySet()))
+ {
+ Notification notification = notifications.get(eventType);
+
+ for (String actionType
+ : new Vector<String>(notification.getActions().keySet()))
+ removeEventNotificationAction(eventType, actionType);
+
+ removeEventNotification(eventType);
+ }
+
+ for (Map.Entry<String, Notification> entry
+ : defaultNotifications.entrySet())
+ {
+ String eventType = entry.getKey();
+ Notification notification = entry.getValue();
+
+ for (NotificationAction action : notification.getActions().values())
+ registerNotificationForEvent(eventType, action);
+ }
+ }
+
+ /**
+ * Saves the event notification given by these parameters through the
+ * <tt>ConfigurationService</tt>.
+ *
+ * @param eventType the name of the event
+ * @param action the notification action to change
+ * @param isActive is the event active
+ * @param isDefault is it a default one
+ */
+ private void saveNotification( String eventType,
+ NotificationAction action,
+ boolean isActive,
+ boolean isDefault)
{
String eventTypeNodeName = null;
String actionTypeNodeName = null;
@@ -1227,11 +1144,24 @@ class NotificationServiceImpl
eventTypeNodeName = eventTypeRootPropName;
}
- // If we didn't find the given event type in the configuration
- // there is not need to further check
+ // If we didn't find the given event type in the configuration we save
+ // it here.
if(eventTypeNodeName == null)
{
- throw new IllegalArgumentException("Missing event type node");
+ eventTypeNodeName = NOTIFICATIONS_PREFIX
+ + ".eventType"
+ + Long.toString(System.currentTimeMillis());
+
+ configService.setProperty(eventTypeNodeName, eventType);
+ }
+
+ // if we set active/inactive for the whole event notification
+ if(action == null)
+ {
+ configService.setProperty(
+ eventTypeNodeName + ".active",
+ Boolean.toString(isActive));
+ return;
}
// Go through contained actions.
@@ -1249,43 +1179,121 @@ class NotificationServiceImpl
Map<String, Object> configProperties = new HashMap<String, Object>();
- // If we didn't find the given actionType in the configuration
- // there is no need to further check
+ // If we didn't find the given actionType in the configuration we save
+ // it here.
if(actionTypeNodeName == null)
{
- throw new IllegalArgumentException("Missing action type node");
+ actionTypeNodeName = actionPrefix
+ + ".actionType"
+ + Long.toString(System.currentTimeMillis());
+
+ configProperties.put(actionTypeNodeName, action.getActionType());
}
- return
- (String)configService
- .getProperty(actionTypeNodeName + "." + property);
+ if(action instanceof SoundNotificationAction)
+ {
+ SoundNotificationAction soundAction
+ = (SoundNotificationAction) action;
+
+ configProperties.put(
+ actionTypeNodeName + ".soundFileDescriptor",
+ soundAction.getDescriptor());
+
+ configProperties.put(
+ actionTypeNodeName + ".loopInterval",
+ soundAction.getLoopInterval());
+
+ configProperties.put(
+ actionTypeNodeName + ".isSoundNotificationEnabled",
+ soundAction.isSoundNotificationEnabled());
+
+ configProperties.put(
+ actionTypeNodeName + ".isSoundPlaybackEnabled",
+ soundAction.isSoundPlaybackEnabled());
+
+ configProperties.put(
+ actionTypeNodeName + ".isSoundPCSpeakerEnabled",
+ soundAction.isSoundPCSpeakerEnabled());
+ }
+ else if(action instanceof PopupMessageNotificationAction)
+ {
+ PopupMessageNotificationAction messageAction
+ = (PopupMessageNotificationAction) action;
+
+ configProperties.put(
+ actionTypeNodeName + ".defaultMessage",
+ messageAction.getDefaultMessage());
+ }
+ else if(action instanceof LogMessageNotificationAction)
+ {
+ LogMessageNotificationAction logMessageAction
+ = (LogMessageNotificationAction) action;
+
+ configProperties.put(
+ actionTypeNodeName + ".logType",
+ logMessageAction.getLogType());
+ }
+ else if(action instanceof CommandNotificationAction)
+ {
+ CommandNotificationAction commandAction
+ = (CommandNotificationAction) action;
+
+ configProperties.put(
+ actionTypeNodeName + ".commandDescriptor",
+ commandAction.getDescriptor());
+ }
+
+ configProperties.put(
+ actionTypeNodeName + ".enabled",
+ Boolean.toString(isActive));
+
+ configProperties.put(
+ actionTypeNodeName + ".default",
+ Boolean.toString(isDefault));
+
+ configService.setProperties(configProperties);
}
/**
- * Deletes all registered events and actions
- * and registers and saves the default events as current.
+ * Finds the <tt>EventNotification</tt> corresponding to the given
+ * <tt>eventType</tt> and marks it as activated/deactivated.
+ *
+ * @param eventType the name of the event, which actions should be activated
+ * /deactivated.
+ * @param isActive indicates whether to activate or deactivate the actions
+ * related to the specified <tt>eventType</tt>.
*/
- public void restoreDefaults()
+ public void setActive(String eventType, boolean isActive)
{
- for (String eventType : new Vector<String>(notifications.keySet()))
- {
- Notification notification = notifications.get(eventType);
+ Notification eventNotification
+ = notifications.get(eventType);
- for (String actionType
- : new Vector<String>(notification.getActions().keySet()))
- removeEventNotificationAction(eventType, actionType);
+ if(eventNotification == null)
+ return;
- removeEventNotification(eventType);
- }
+ eventNotification.setActive(isActive);
+ saveNotification(eventType, null, isActive, false);
+ }
- for (Map.Entry<String, Notification> entry
- : defaultNotifications.entrySet())
- {
- String eventType = entry.getKey();
- Notification notification = entry.getValue();
+ /**
+ * Stops a notification if notification is continuous, like playing sounds
+ * in loop. Do nothing if there are no such events currently processing.
+ *
+ * @param data the data that has been returned when firing the event..
+ */
+ public void stopNotification(NotificationData data)
+ {
+ Iterable<NotificationHandler> soundHandlers
+ = getActionHandlers(NotificationAction.ACTION_SOUND);
- for (NotificationAction action : notification.getActions().values())
- registerNotificationForEvent(eventType, action);
+ // There could be no sound action handler for this event type
+ if (soundHandlers != null)
+ {
+ for (NotificationHandler handler : soundHandlers)
+ {
+ if (handler instanceof SoundNotificationHandler)
+ ((SoundNotificationHandler) handler).stop(data);
+ }
}
}
}
diff --git a/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java b/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java
index e8b5716..d9cdfd0 100644
--- a/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java
+++ b/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java
@@ -29,11 +29,12 @@ public interface PopupMessageNotificationHandler
* appropriate
* @param tag additional info to be used by the notification handler
*/
- public void popupMessage(PopupMessageNotificationAction action,
- String title,
- String message,
- byte[] icon,
- Object tag);
+ public void popupMessage(
+ PopupMessageNotificationAction action,
+ String title,
+ String message,
+ byte[] icon,
+ Object tag);
/**
* Adds a listener for <tt>SystrayPopupMessageEvent</tt>s posted when user
diff --git a/src/net/java/sip/communicator/util/dns/ConfigurableDnssecResolver.java b/src/net/java/sip/communicator/util/dns/ConfigurableDnssecResolver.java
index 0a5f4fb..cae92fc 100644
--- a/src/net/java/sip/communicator/util/dns/ConfigurableDnssecResolver.java
+++ b/src/net/java/sip/communicator/util/dns/ConfigurableDnssecResolver.java
@@ -142,9 +142,10 @@ public class ConfigurableDnssecResolver
|| last.before(new Date(new Date().getTime() - 1000*60*5)))
{
DnsUtilActivator.getNotificationService().fireNotification(
- EVENT_TYPE,
- R.getI18NString("util.dns.INSECURE_ANSWER_TITLE"),
- text, null, null);
+ EVENT_TYPE,
+ R.getI18NString("util.dns.INSECURE_ANSWER_TITLE"),
+ text,
+ null);
lastNotifications.put(text, new Date());
}
throw new DnssecRuntimeException(text);
diff --git a/test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java b/test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java
index babec92..01b6f3b 100644
--- a/test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java
+++ b/test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java
@@ -10,11 +10,9 @@ import junit.framework.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
-import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
-
/**
* Test suite for the popup message handler interface.
* @author Symphorien Wanko
@@ -22,10 +20,6 @@ import org.osgi.framework.*;
public class TestPopupMessageHandler
extends TestCase
{
- /** Logger for this class */
- private static final Logger logger
- = Logger.getLogger(TestPopupMessageHandler.class);
-
/**
* the <tt>SystrayService</tt> reference we will get from bundle
* context to register ours handlers
@@ -121,7 +115,6 @@ public class TestPopupMessageHandler
{
serviceReference = bc.getServiceReference(
NotificationService.class.getName());
-
notificationService
= (NotificationService) bc.getService(serviceReference);
@@ -129,7 +122,6 @@ public class TestPopupMessageHandler
NotificationAction.ACTION_POPUP_MESSAGE,
messageStart,
messageStart,
- null,
null);
}