diff --git a/source/org/jivesoftware/smackx/LastActivityManager.java b/source/org/jivesoftware/smackx/LastActivityManager.java index 857594205..a9d1f12b8 100644 --- a/source/org/jivesoftware/smackx/LastActivityManager.java +++ b/source/org/jivesoftware/smackx/LastActivityManager.java @@ -26,45 +26,57 @@ import org.jivesoftware.smack.filter.IQTypeFilter; import org.jivesoftware.smack.filter.PacketIDFilter; import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.packet.Presence; +import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.smackx.packet.LastActivity; /** - * A last activity manager for handling information about the last activity associated - * with a Jabber ID. A manager handles incoming LastActivity requests of existing - * Connections. It also allows to request last activity information of other users.
- * - * LastActivity (JEP-012) based on the sending JID's type allows for retrieval of: + * A last activity manager for handling information about the last activity + * associated with a Jabber ID. A manager handles incoming LastActivity requests + * of existing Connections. It also allows to request last activity information + * of other users. + *
+ * + * LastActivity (XEP-0012) based on the sending JID's type allows for retrieval + * of: *
- * + * + * For example to get the idle time of a user logged in a resource, simple send + * the LastActivity packet to them, as in the following code: + *
+ * *
- * Connection con = new XMPPConnection("jabber.org"); - * con.login("john", "doe"); - * LastActivity activity = LastActivity.getLastActivity(con, "xray@jabber.org/Smack"); + * Connection con = new XMPPConnection("jabber.org"); + * con.login("john", "doe"); + * LastActivity activity = LastActivity.getLastActivity(con, "xray@jabber.org/Smack"); *- * - * To get the lapsed time since the last user logout is the same as above but with - * out the resource: + * + * To get the lapsed time since the last user logout is the same as above but + * with out the resource: + * *
- * LastActivity activity = LastActivity.getLastActivity(con, "xray@jabber.org"); + * LastActivity activity = LastActivity.getLastActivity(con, "xray@jabber.org"); *- * - * To get the uptime of a host, you simple send the LastActivity packet to it, as in the - * following code example:
- * + * + * To get the uptime of a host, you simple send the LastActivity packet to it, + * as in the following code example: + *
+ * *
- * LastActivity activity = LastActivity.getLastActivity(con, "jabber.org"); + * LastActivity activity = LastActivity.getLastActivity(con, "jabber.org"); *- * + * * @author Gabriel Guardincerri + * @see XEP-0012: Last + * Activity */ public class LastActivityManager { @@ -84,8 +96,9 @@ public class LastActivityManager { /** * Creates a last activity manager to response last activity requests. - * - * @param connection The Connection that the last activity requests will use. + * + * @param connection + * The Connection that the last activity requests will use. */ private LastActivityManager(Connection connection) { this.connection = connection; @@ -93,9 +106,28 @@ public class LastActivityManager { // Listen to all the sent messages to reset the idle time on each one connection.addPacketSendingListener(new PacketListener() { public void processPacket(Packet packet) { + Presence presence = (Presence) packet; + Presence.Mode mode = presence.getMode(); + if (mode == null) return; + switch (mode) { + case available: + case chat: + // We assume that only a switch to available and chat indicates user activity + // since other mode changes could be also a result of some sort of automatism + resetIdleTime(); + } + } + }, new PacketTypeFilter(Presence.class)); + + connection.addPacketListener(new PacketListener() { + @Override + public void processPacket(Packet packet) { + Message message = (Message) packet; + // if it's not an error message, reset the idle time + if (message.getType() == Message.Type.error) return; resetIdleTime(); } - }, null); + }, new PacketTypeFilter(Message.class)); // Register a listener for a last activity query connection.addPacketListener(new PacketListener() { @@ -112,6 +144,8 @@ public class LastActivityManager { } }, new AndFilter(new IQTypeFilter(IQ.Type.GET), new PacketTypeFilter(LastActivity.class))); + ServiceDiscoveryManager.getInstanceFor(connection).addFeature(LastActivity.NAMESPACE); + resetIdleTime(); } /** @@ -119,17 +153,24 @@ public class LastActivityManager { * sent. */ private void resetIdleTime() { - lastMessageSent = System.currentTimeMillis(); + long now = System.currentTimeMillis(); + synchronized (this) { + lastMessageSent = now; + } } /** * The idle time is the lapsed time between the last message sent and now. - * + * * @return the lapsed time between the last message sent and now. */ private long getIdleTime() { + long lms; long now = System.currentTimeMillis(); - return ((now - lastMessageSent) / 1000); + synchronized (this) { + lms = lastMessageSent; + } + return ((now - lms) / 1000); } /** @@ -137,26 +178,26 @@ public class LastActivityManager { * (i.e., a JID of the form of 'user@host/resource') then the last activity * is the idle time of that connected resource. On the other hand, when the * jid is a bare JID (e.g. 'user@host') then the last activity is the lapsed - * time since the last logout or 0 if the user is currently logged in. Moreover, - * when the jid is a server or component (e.g., a JID of the form 'host') the - * last activity is the uptime. - * - * @param con the current Connection. - * @param jid the JID of the user. + * time since the last logout or 0 if the user is currently logged in. + * Moreover, when the jid is a server or component (e.g., a JID of the form + * 'host') the last activity is the uptime. + * + * @param con + * the current Connection. + * @param jid + * the JID of the user. * @return the LastActivity packet of the jid. - * @throws XMPPException thrown if a server error has occured. + * @throws XMPPException + * thrown if a server error has occured. */ - public static LastActivity getLastActivity(Connection con, String jid) - throws XMPPException { + public static LastActivity getLastActivity(Connection con, String jid) throws XMPPException { LastActivity activity = new LastActivity(); activity.setTo(jid); - PacketCollector collector = - con.createPacketCollector(new PacketIDFilter(activity.getPacketID())); + PacketCollector collector = con.createPacketCollector(new PacketIDFilter(activity.getPacketID())); con.sendPacket(activity); - LastActivity response = - (LastActivity) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); + LastActivity response = (LastActivity) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); // Cancel the collector. collector.cancel(); @@ -167,6 +208,23 @@ public class LastActivityManager { throw new XMPPException(response.getError()); } return response; - } + } + /** + * Returns true if Last Activity (XEP-0012) is supported by a given JID + * + * @param connection the connection to be used + * @param jid a JID to be tested for Last Activity support + * @return true if Last Activity is supported, otherwise false + */ + public static boolean isLastActivitySupported(Connection connection, String jid) { + try { + DiscoverInfo result = + ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid); + return result.containsFeature(LastActivity.NAMESPACE); + } + catch (XMPPException e) { + return false; + } + } } diff --git a/source/org/jivesoftware/smackx/packet/LastActivity.java b/source/org/jivesoftware/smackx/packet/LastActivity.java index 30c616f0b..6f4f15a11 100644 --- a/source/org/jivesoftware/smackx/packet/LastActivity.java +++ b/source/org/jivesoftware/smackx/packet/LastActivity.java @@ -20,6 +20,8 @@ package org.jivesoftware.smackx.packet; +import java.io.IOException; + import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.Connection; @@ -29,10 +31,11 @@ import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.util.StringUtils; import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; /** * A last activity IQ for retrieving information about the last activity associated with a Jabber ID. - * LastActivity (JEP-012) allows for retrieval of how long a particular user has been idle and the + * LastActivity (XEP-0012) allows for retrieval of how long a particular user has been idle and the * message the specified when doing so. Use {@link org.jivesoftware.smackx.LastActivityManager} * to get the last activity of a user. * @@ -40,6 +43,8 @@ import org.xmlpull.v1.XmlPullParser; */ public class LastActivity extends IQ { + public static final String NAMESPACE = "jabber:iq:last"; + public long lastActivity = -1; public String message; @@ -49,12 +54,11 @@ public class LastActivity extends IQ { public String getChildElementXML() { StringBuilder buf = new StringBuilder(); - buf.append("