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: *

    *
  1. How long a particular user has been idle - *
  2. How long a particular user has been logged-out and the message the specified when doing so. + *
  3. How long a particular user has been logged-out and the message the + * specified when doing so. *
  4. How long a host has been up. *
*

- * - * 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:

- * + * + * 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(""); + buf.append(""); return buf.toString(); } @@ -100,26 +104,29 @@ public class LastActivity extends IQ { super(); } - public IQ parseIQ(XmlPullParser parser) throws Exception { + public IQ parseIQ(XmlPullParser parser) throws XMPPException, XmlPullParserException { if (parser.getEventType() != XmlPullParser.START_TAG) { - throw new IllegalStateException("Parser not in proper position, or bad XML."); + throw new XMPPException("Parser not in proper position, or bad XML."); } LastActivity lastActivity = new LastActivity(); + String seconds = parser.getAttributeValue("", "seconds"); + String message = null; try { - String seconds = parser.getAttributeValue("", "seconds"); - String message = parser.nextText(); - if (seconds != null) { - long xmlSeconds = new Double(seconds).longValue(); - lastActivity.setLastActivity((int)xmlSeconds); - } - - if (message != null) { - lastActivity.setMessage(message); + message = parser.nextText(); + } catch (IOException e1) { + // Ignore + } + if (seconds != null) { + try { + lastActivity.setLastActivity(Long.parseLong(seconds)); + } catch (NumberFormatException e) { + // Ignore } } - catch (Exception e) { - e.printStackTrace(); + + if (message != null) { + lastActivity.setMessage(message); } return lastActivity; }