Обнаружение неактивности пользователя в настольном приложении - PullRequest
2 голосов
/ 24 февраля 2012

У меня есть приложение в Eclipse RCP, в котором я хочу запустить функцию с именем LogOutUser (), если пользователь оставляет свое приложение без дела, скажем, в течение пяти минут.

Как мне это сделать?

Ответы [ 3 ]

1 голос
/ 24 февраля 2012

Если вы посмотрите в комплекте org.eclipse.ui.ide.application, то есть класс org.eclipse.ui.internal.ide.application.IDEIdleHelper, который пытается выполнить gc после интервала бездействия пользователя. Вероятно, вы можете повторно использовать логику, которая обнаруживает бездействие

1 голос
/ 25 февраля 2012

Обычно я использую Display.addFilter(eventType, listener) для типов событий, которые должны поддерживать сеанс в сочетании с Display.timerExec(milliseconds, runnable), который периодически запускается и проверяет последнее интересное событие.

Я использую milliseconds = 5000, поэтому период составляет от 5 минут до 5 минут 5 секунд, прежде чем пользователь выходит из системы (или что-то еще ...). Также я слушаю для типов событий SWT (в 3.7) KeyDown, KeyUp, MouseDown, MouseUp, MouseVerticalWheel, MouseHorizontalWheel MouseDoubleClick, Touch, Gesture, Activate , Iconify, Deiconify, Move и Resize.

1 голос
/ 24 февраля 2012

Я не знаю, поддерживает ли структура RCP это внутренне. Тем не менее, я написал свой собственный «вспомогательный» класс, который является менеджером сеансов с одним клиентом. 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);

}
...