检测桌面应用程序中的用户不活动

时间:2012-02-24 04:17:47

标签: java eclipse-rcp

我在Eclipse RCP中有一个应用程序,如果用户将他/她的应用程序空闲,例如五分钟,我想要触发一个名为“LogOutUser()”的函数。

我该怎么做?

3 个答案:

答案 0 :(得分:1)

我不知道RCP框架是否在内部支持这一点。但是,我编写了自己的“helper”类,它是一个单例客户端会话管理器。 Eclipse本身不会知道如何连接到您的数据源。在我的例子中,我使用EJB3调用连接并监听JMS队列和主题。

我的课程是为了检测数据源或“服务器”何时停机而编写的。当服务器启动时它也会重新连接。通过侦听服务器发送的心跳DTO来检测服务器不活动。该反馈对于呈现给用户是有用的。我已经调整了这个类来满足用户界面不活动的需要。

课程非常简单。它是一个单例,因此可以在客户端RCP应用程序中的任何位置简单地调用它。心跳使用观察者,因此您必须添加HeartBeatEventListener以挂钩此功能。您可以调整类以对用户界面不活动执行相同操作。但是,我刚刚提供了updateUserInterfaceActivity()方法,您必须在有用户活动时调用该方法。也许这可以挂钩到全局鼠标全局键盘事件处理程序。

我还添加了TrayItem来更新用户...

这是班级:

package com.kingsleywebb.clientsessionmanagement;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolTip;
import org.eclipse.swt.widgets.TrayItem;

import com.kingsleywebb.clientsessionmanagement.entity.HeartbeatDTO;

public class ClientSessionManagement implements HeartbeatEventListener {

    private static final Image IMG_CONNECTED = null;  // Set this to a "connected image"
    private static final Image IMG_DISCONNECTED = null;  // Set this to a "disconnected image"

    private static final long CONNECTION_INACTIVITY_TIME_MS = 30000L; // 30 seconds
    private static final long USER_INTERFACE_INACTIVITY_TIME_MS = 300000L; // 5 minutes

    private static final Log LOG = LogFactory.getLog(ClientSessionManagement.class);
    private static ClientSessionManagement theInstance = null;
    private static long connectionTimestamp = 0;
    private static long userInterfaceActivityTimestamp = 0;

    private synchronized static void createInstance() {
        if (theInstance == null) {
            theInstance = new ClientSessionManagement();
        }
    }

    public static ClientSessionManagement getInstance() {
        if (theInstance == null) {
            createInstance();
        }
        return theInstance;
    }

    private ClientSessionManagement() {

        this.connectionListenerList = new ArrayList<ConnectionListener>();

        updateConnectionTimestamp();

        Cron cron = new Cron();
        Thread cronThread = new Thread(cron);       
        cronThread.start();
    }

    private boolean connected = true;

    private ToolTip toolTipConnected;
    private ToolTip toolTipDisconnected;
    private TrayItem trayItem = null;
    private String appName = null;
    private String version = null;
    private String whiteLabel = null;
    private String userName = null;
    private String deskName = null;
    private String serverName = null;
    private String userMnemonic = null;
    private MenuItem miShowPopups;
    private MenuItem miSoundBeep;

    private List<ConnectionListener> connectionListenerList;

    private void updateConnectionTimestamp() {
        ClientSessionManagement.connectionTimestamp = System.currentTimeMillis();
    }

    private synchronized long getLastHeartbeatInMsAgo() {
        return System.currentTimeMillis() - ClientSessionManagement.connectionTimestamp;
    }

    public synchronized void updateHeartbeat() {
        updateConnectionTimestamp();        
    }

    public synchronized void checkHeartbeatInterval() {
        if (getLastHeartbeatInMsAgo() < CONNECTION_INACTIVITY_TIME_MS) {
            showConnected();
        }
        else {
            showDisconnected();
        }
    }

    private void updateUserInterfaceActivityTimestamp() {
        ClientSessionManagement.userInterfaceActivityTimestamp = System.currentTimeMillis();
    }

    private synchronized long getLastUserInterfaceActivityInMsAgo() {
        return System.currentTimeMillis() - ClientSessionManagement.userInterfaceActivityTimestamp;
    }

    public synchronized void updateUserInterfaceActivity() {
        updateUserInterfaceActivityTimestamp();
    }

    public synchronized void checkUserInterfaceActivityInterval() {
        if (getLastUserInterfaceActivityInMsAgo() > USER_INTERFACE_INACTIVITY_TIME_MS) {
            logoutUser();
        }
    }

    private void logoutUser() {
        // Implement logout functionality here      
    }

    private void showConnected() {
        if (!connected) {
            connected = true;

            Display.getDefault().asyncExec(new Runnable() {
                public void run() {
                    // Update icon
                    if (trayItem != null) {
                        trayItem.setImage(ClientSessionManagement.IMG_CONNECTED);
                        trayItem.getToolTip().setVisible(false);
                        trayItem.setToolTip(toolTipConnected);                      
                        trayItem.getToolTip().setVisible(true);
                    }

                    // Update hover tooltip
                    updateHoverTooltip();
                }               
            });

            notifyConnectionListeners();            
        }
    }

    private void showDisconnected() {
        if (connected) {
            connected = false;

            Display.getDefault().asyncExec(new Runnable() {
                public void run() {

                    // Update icon
                    if (trayItem != null) {
                        trayItem.setImage(ClientSessionManagement.IMG_DISCONNECTED);
                        trayItem.getToolTip().setVisible(false);
                        trayItem.setToolTip(toolTipDisconnected);
                        trayItem.getToolTip().setVisible(true);
                    }

                    // Update hover tooltip
                    updateHoverTooltip();                   
                }               
            });

            notifyConnectionListeners();
        }
    }

    private void updateHoverTooltip() {
        if (trayItem != null) {

            // Application info
            String applicationInfo = null;
            if (appName != null && version != null && whiteLabel != null) {
                // appName* | version | whitelabel
                applicationInfo =  "  Application: " + "  " + appName + " " + version + " [" + whiteLabel + "]\r\n";
            }           

            // User info
            String userInfo = null;
            if (userName != null && deskName != null && serverName != null) {
                userInfo = "  User: " + "  " + userName + " (" + deskName + ") on " + serverName + "\r\n";              
            }

            // Connection info
            String connectionInfo = connected ? "  Server Connected" : "  SERVER DISCONNECTED!!!";

            String status = connectionInfo + "\r\n\r\n" + (applicationInfo != null ? applicationInfo : "") +
                (userInfo != null ? userInfo : "");

            trayItem.setToolTipText(status);
            LOG.info(status);
        }
    }

    public void setTrayItem(Shell shell, TrayItem trayItem) {
        this.trayItem = trayItem;

        /* 
         * Property files to persist these settings - removed for simplicity
         * 
         * final WorkstationProperties p = WorkstationProperties.getInstance();
         * boolean showNotificationPopups = !"No".equalsIgnoreCase(p.getProperty("notifications.showNotificationPopups"));
         * boolean soundNotificationBeep = !"No".equalsIgnoreCase(p.getProperty("notifications.soundNotificationBeep"));        
         */

        boolean showNotificationPopups = true;
        boolean soundNotificationBeep = true;

        final Menu menu = new Menu (shell, SWT.POP_UP);
        miShowPopups = new MenuItem (menu, SWT.CHECK);
        miShowPopups.setSelection(showNotificationPopups);
        miShowPopups.setText("Show Notification Popups");
        miShowPopups.addListener (SWT.Selection, new Listener () {
            public void handleEvent (Event event) {
                LOG.info("notifications.showNotificationPopups = " + miShowPopups.getSelection());
                // Property files to persist these settings - removed for simplicity        
                //p.setProperty("notifications.showNotificationPopups", miShowPopups.getSelection() ? "Yes" : "No");
            }
        });

        miSoundBeep = new MenuItem (menu, SWT.CHECK);
        miSoundBeep.setSelection(soundNotificationBeep);
        miSoundBeep.setText("Play Notification Beep");
        miSoundBeep.addListener (SWT.Selection, new Listener () {
            public void handleEvent (Event event) {
                LOG.info("notifications.soundNotificationBeep = " + miSoundBeep.getSelection());
                // Property files to persist these settings - removed for simplicity    
                //p.setProperty("notifications.soundNotificationBeep", miSoundBeep.getSelection() ? "Yes" : "No");
            }
        });

        this.trayItem.addListener (SWT.MenuDetect, new Listener () {
            public void handleEvent (Event event) {
                menu.setVisible (true);
            }
        });

        toolTipConnected = new ToolTip(shell, SWT.BALLOON);
        toolTipConnected.setText((appName != null ? appName : "<Application Name>") + " Status");
        toolTipConnected.setMessage("Connected to server.");
        toolTipConnected.setLocation(600, 600);
        toolTipConnected.setVisible(false);

        toolTipDisconnected = new ToolTip(shell, SWT.ICON_WARNING);
        toolTipDisconnected.setText((appName != null ? appName : "<Application Name>") + " Status");
        toolTipDisconnected.setMessage("DISCONNECTED from server.");
        toolTipDisconnected.setLocation(500, 500);
        toolTipDisconnected.setVisible(false);

        this.trayItem.setToolTip(toolTipConnected);
    }

    public boolean isShowPopups() {
        return miShowPopups.getSelection();
    }

    public boolean isSoundBeep() {
        return miSoundBeep.getSelection();
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public void setWhiteLabel(String whiteLabel) {
        this.whiteLabel = whiteLabel;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setDeskName(String deskName) {
        this.deskName = deskName;
    }

    public void setServerName(String serverName) {
        this.serverName = serverName;
        updateHoverTooltip();
    }

    public String getUserMnemonic() {
        return userMnemonic;
    }

    public void setUserMnemonic(String userMnemonic) {
        this.userMnemonic = userMnemonic;
    }

    public void heartbeatArrived(HeartbeatDTO heartbeatDTO) {               
        updateHeartbeat();          
    }

    public boolean isConnected() {
        return connected;
    }

    public boolean addConnectionListener(ConnectionListener connectionListener) {
        return connectionListenerList.add(connectionListener);
    }

    public boolean removeConnectionListener(ConnectionListener connectionListener) {
        return connectionListenerList.remove(connectionListener);
    }

    public void notifyConnectionListeners() {
        for (Iterator<ConnectionListener> i = connectionListenerList.iterator(); i.hasNext();) {
            ConnectionListener connectionListener = i.next();
            if (connected) {
                connectionListener.connected();
            }
            else {
                connectionListener.disconnected();
            }
        }
    }

    /**
     * 
     * @author Kingsley Webb
     *
     * Check heartbeat interval periodically display warning to user accordingly.
     */
    class Cron implements Runnable {

        public void run() {

            // Wait 15s extra before 1st check
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                LOG.error(e);
            }

            while (true) {
                // Check every 5s - increase for better performance, but you get the idea...
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    LOG.error(e);
                }           

                checkHeartbeatInterval();
                checkUserInterfaceActivityInterval();
            }           
        }

    }

}

其他一些支持课程:

package com.kingsleywebb.clientsessionmanagement;

public interface ConnectionListener {

    public void connected();
    public void disconnected();

}

package com.kingsleywebb.clientsessionmanagement;

import com.kingsleywebb.clientsessionmanagement.entity.HeartbeatDTO;

public interface HeartbeatEventListener {

     public void heartbeatArrived(HeartbeatDTO heartbeatDTO);

}

答案 1 :(得分:1)

如果您查看软件包org.eclipse.ui.ide.application,那么有一个类org.eclipse.ui.internal.ide.application.IDEIdleHelper会在用户不活动的间隔后尝试执行gc。可能您可以重用检测不活动的逻辑

答案 2 :(得分:1)

我通常使用Display.addFilter(eventType, listener)来保存会话的活动类型与定期运行的Display.timerExec(milliseconds, runnable)结合并测试最后一个有趣的事件。

我使用milliseconds = 5000所以在用户退出之前(或者其他......),这段时间是5分钟到5分钟5秒。我也听取了SWT事件类型(在3.7中)KeyDownKeyUpMouseDownMouseUpMouseVerticalWheelMouseHorizontalWheel {{1 },MouseDoubleClickTouchGestureActivateIconifyDeiconifyMove