How do you get system idle time?

I’ve been trying to get Spark to show the idle time of contacts and I’ve made a patch, but it’s a little quirky. It’s actually a patch to Smack and to Spark.

I had to patch Smack because it seemed to be the part that kept track of the idle time, is this correct? The problem is that the idle is based on packets, not the computer state. Is there a way to get the system idle instead? I changed it to reset the idle if the packet was a chat message or a pressence message instead of every packet because then the idle request itself would reset it.

The patch to Spark was just to add the information to the pop up window so it will say ‘Idle for x minutes’ if the user is idle or ‘Available/offline since h:mm a’ along with their status.

Smack Patch:

### Eclipse Workspace Patch 1.0
#P Smack
Index: source/org/jivesoftware/smackx/LastActivityManager.java
===================================================================
--- source/org/jivesoftware/smackx/LastActivityManager.java    (revision 12370)
+++ source/org/jivesoftware/smackx/LastActivityManager.java    (working copy)
@@ -28,6 +28,8 @@ import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smackx.packet.LastActivity;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Presence; /**
  * A last activity manager for handling information about the last activity associated
@@ -93,7 +95,13 @@
         // Listen to all the sent messages to reset the idle time on each one
         connection.addPacketSendingListener(new PacketListener() {
             public void processPacket(Packet packet) {
-                resetIdleTime();
+                if (packet instanceof Presence) {
+                    String type = ((Presence) packet).getType().toString();
+                    if(type.compareTo("available")==0) resetIdleTime();
+                } else if(packet instanceof Message) {
+                    String type = ((Message) packet).getType().toString();
+                    if(type.compareTo("chat")==0) resetIdleTime();
+                }
             }
         }, null);

Spark patch:

### Eclipse Workspace Patch 1.0
#P Spark
Index: src/java/org/jivesoftware/spark/ui/ContactList.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ContactList.java    (revision 12345)
+++ src/java/org/jivesoftware/spark/ui/ContactList.java    (working copy)
@@ -1631,23 +1631,44 @@
             private static final long serialVersionUID = -4884230635430933060L;              public void actionPerformed(ActionEvent actionEvent) {
-                try {
-                    LastActivity activity = LastActivityManager.getLastActivity(SparkManager.getConnection(), item.getJID());
-                    long idleTime = (activity.getIdleTime() * 1000);
-                    String time = ModelUtil.getTimeFromLong(idleTime);
-                    JOptionPane.showMessageDialog(getGUI(), Res.getString("message.idle.for", time), Res.getString("title.last.activity"), JOptionPane.INFORMATION_MESSAGE);
+                    String jid = item.getJID();
+                    String client = item.getPresence().getFrom();
+
+                    if ((client != null) && (client.lastIndexOf("/") != -1)) {
+                        client = client.substring(client.lastIndexOf("/") + 1);
+                    } else {
+                        client = "";
+                    }
+
+                    try {
+                        if (item.getPresence().getType() != Presence.Type.unavailable) {
+                            jid += ("/" + client);
+                        }
+
+                        LastActivity activity = LastActivityManager.getLastActivity(SparkManager.getConnection(),
+                                jid);
+                        long idleTime = (activity.getIdleTime() * 1000);
+                        String time = ModelUtil.getTimeFromLong(idleTime);
+                        JOptionPane.showMessageDialog(getGUI(),
+                            Res.getString("message.idle.for", time),
+                            Res.getString("title.last.activity"),
+                            JOptionPane.INFORMATION_MESSAGE);
+                    } catch (Exception e1) {
+                        JOptionPane.showMessageDialog(getGUI(),
+                            Res.getString(
+                                "message.unable.to.retrieve.last.activity",
+                                item.getJID()), Res.getString("title.error"),
+                            JOptionPane.ERROR_MESSAGE);
+                    }
                 }
-                catch (Exception e1) {
-                    JOptionPane.showMessageDialog(getGUI(), Res.getString("message.unable.to.retrieve.last.activity", item.getJID()), Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
-                }
+            }; -            }
-        };
-
         lastActivityAction.putValue(Action.NAME, Res.getString("menuitem.view.last.activity"));
         lastActivityAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_USER1_STOPWATCH)); -        if (contactGroup == offlineGroup) {
+        if (item.getPresence().isAway() ||
+                (item.getPresence().getType() == Presence.Type.unavailable) ||
+                (item.getPresence().getType() == null)) {
             popup.add(lastActivityAction);
         } Index: src/java/org/jivesoftware/spark/ui/ContactInfoWindow.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ContactInfoWindow.java    (revision 12345)
+++ src/java/org/jivesoftware/spark/ui/ContactInfoWindow.java    (working copy)
@@ -19,6 +19,9 @@
  */ package org.jivesoftware.spark.ui; +import org.jivesoftware.smackx.LastActivityManager;
+import org.jivesoftware.smackx.packet.LastActivity;
+import org.jivesoftware.smackx.packet.VCard; import java.awt.Color; import java.awt.Dimension; import java.awt.Font;
@@ -31,6 +34,10 @@ import java.net.MalformedURLException; import java.net.URL; +import java.text.SimpleDateFormat;
+
+import java.util.Date;
+ import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JLabel;
@@ -44,6 +51,7 @@ import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.packet.VCard; import org.jivesoftware.spark.SparkManager;
+import org.jivesoftware.spark.ui.ContactItem; import org.jivesoftware.spark.util.GraphicUtils; import org.jivesoftware.spark.util.ModelUtil; import org.jivesoftware.spark.util.log.Log;
@@ -208,13 +216,63 @@          String status = contactItem.getStatus();
         if (!ModelUtil.hasLength(status)) {
-            if (contactItem.getPresence() == null || contactItem.getPresence().getType() == Presence.Type.unavailable) {
+            if ((contactItem.getPresence() == null) ||
+                    (contactItem.getPresence().getType() == Presence.Type.unavailable)) {
                 status = Res.getString("offline");
-            }
-            else {
+            } else {
                 status = Res.getString("online");
             }
         }
+
+        String jid = contactItem.getJID();
+        String client = contactItem.getPresence().getFrom();
+
+        if ((client != null) && (client.lastIndexOf("/") != -1)) {
+            client = client.substring(client.lastIndexOf("/") + 1);
+
+            if (!status.equals(Res.getString("offline"))) {
+                jid += ("/" + client);
+            }
+        } else {
+            client = "";
+        }
+
+        if (!client.equalsIgnoreCase("AgileMessenger")) {
+            try {
+                LastActivity activity = LastActivityManager.getLastActivity(SparkManager.getConnection(),
+                        jid);
+
+                //Log.error(jid+":"+status+":"+activity.getIdleTime());
+                long idleTime = (activity.getIdleTime() * 1000);
+
+                if (idleTime > 0) {
+                    SimpleDateFormat format = new SimpleDateFormat("M/d/yy");
+                    Date l = new Date();
+                    String curDay = format.format(l);
+                    l.setTime(l.getTime() - idleTime);
+
+                    //If idleTime is within today show the time, otherwise, show the day, date, and time
+                    if (curDay.equals(format.format(l))) {
+                        format = new SimpleDateFormat("h:mm a");
+                    } else {
+                        format = new SimpleDateFormat("EEE M/d/yy h:mm a");
+                    }
+
+                    if (status.equals(Res.getString("offline"))) {
+                        status += (" since " + format.format(l));
+                    } else if (contactItem.getPresence().isAway()) {
+                        status += "\n";
+
+                        String time = ModelUtil.getTimeFromLong(idleTime);
+                        status += Res.getString("message.idle.for", time);
+                    } else {
+                        status += "\n";
+                        status += ("Available since " + format.format(l));
+                    }
+                }
+            } catch (Exception e1) {
+            }
+        }
         statusLabel.setText(status);          Transport transport = TransportUtils.getTransport(StringUtils.parseServer(contactItem.getJID()));

I realized this does have sort of a privacy bug. The idle response is given regardless of the user setting whether to allow idle or not.

Wolf, what do you think about this one? It seems there should be some sort of idle solution.

I’m a little shaky on how smack/spark interact, but I’m guessing the idle requests go to smack without interacting with spark. Is there a way to have a spark preference that controls the idle request being sent?