package chatty.util; import java.awt.AWTEvent; import java.awt.MouseInfo; import java.awt.Point; import java.awt.PointerInfo; import java.awt.Toolkit; import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import javax.swing.Timer; /** * Tracks whether there is user activity. Currently only tracks the moues * location and allows for manual triggering of activity from the rest of the * program. * * This runs in the EDT. * * @author tduva */ public class ActivityTracker { private static final Logger LOGGER = Logger.getLogger(ActivityTracker.class.getName()); private static final int DELAY = 5000; private static final List<ActivityListener> listeners = new ArrayList<>(); private static Point lastLocation; private static long lastMoved = 0; private static long lastActivity = 0; private static Timer timer; /** * Start tracking activity (globally currently only mouse activity, inside * of the program keypresses and mouse actions). */ public static void startTracking() { if (timer == null) { checkMouseLocation(); timer = new Timer(DELAY, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { checkMouseLocation(); } }); timer.start(); Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { @Override public void eventDispatched(AWTEvent event) { triggerActivity(); } }, AWTEvent.KEY_EVENT_MASK + AWTEvent.MOUSE_EVENT_MASK); LOGGER.info("Started tracking user activity.."); } } /** * Manually trigger activity. */ public static void triggerActivity() { lastActivity = System.currentTimeMillis(); informListeners(); } /** * Check if mouse location has changed from previous check. */ private static void checkMouseLocation() { PointerInfo info = MouseInfo.getPointerInfo(); // This can sometimes be null, so check for it (e.g. when Windows' UAC // screen is active) if (info == null) { return; } Point currentLocation = info.getLocation(); if (lastLocation != null && !lastLocation.equals(currentLocation)) { lastMoved = System.currentTimeMillis(); triggerActivity(); } lastLocation = currentLocation; } /** * Get when any activity was last detected. * * @return */ public static long getLastActivityTime() { return lastActivity; } /** * Get how long ago any activity was last detected. * * @return */ public static long getLastActivityAgo() { return System.currentTimeMillis() - lastActivity; } /** * Get when the mouse was last detected moving. * * @return */ public static long getLastMouseMovedTime() { startTracking(); return lastMoved; } /** * Get how long ago the mouse was last detected moving. * * @return */ public static long getLastMouseMovedAgo() { startTracking(); return System.currentTimeMillis() - lastMoved; } /** * Adds a listener that will be informed one time about user activity, then * removed. * * @param listener */ public static void addActivityListener(ActivityListener listener) { if (listener != null) { startTracking(); listeners.add(listener); } } /** * Remove listener, if present. * * @param listener */ public static void removeActivityListener(ActivityListener listener) { listeners.remove(listener); } /** * Inform all current listeners, then remove them. */ private static void informListeners() { Iterator<ActivityListener> it = listeners.iterator(); while (it.hasNext()) { it.next().activity(); it.remove(); } } }