/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.internal.swing.monitor;
import java.awt.AWTEvent;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import javax.swing.SwingUtilities;
import com.windowtester.internal.runtime.monitor.UIThreadMonitorCommon;
import com.windowtester.runtime.IUIContext;
/**
* Monitors the UI Thread and notifies listeners if the UI thread is either hung or idle
* for an extended period of time. This is accomplished by launching a background thread
* (minimum priority) that checks to see if the UI is responsive and processing input. If
* the UI becomes unresponsive or idle for a period longer than expected, then the
* associated {@link com.windowtester.runtime.monitor.IUIThreadMonitorListener} (see
* {@link #setListener(com.windowtester.runtime.monitor.IUIThreadMonitorListener)}) is
* notified.
*/
public class UIThreadMonitorSwing extends UIThreadMonitorCommon {
/**
* The types of AWT events that should occur during a test
*/
protected static final long EVENT_TYPES = AWTEvent.MOUSE_EVENT_MASK | AWTEvent.KEY_EVENT_MASK;
/**
* An AWT Event Listener
*/
public final AWTEventListener _awtEventListener = new AWTEventListener(){
public void eventDispatched(AWTEvent event) {
markEventProcessed();
trace("event processed", event.getID());
}
};
/**
* A runnable to notice responsivenes of the UI thread.
*/
public final Runnable _threadResponsiveRunnable = new Runnable() {
public void run() {
markUIThreadResponsive();
}
};
////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
// //////////////////////////////////////////////////////////////////////////
/**
* Construct a new instance to monitor the health of the user interface thread.
*
* @param uiContext the user interface context (not <code>null</code>)
*/
public UIThreadMonitorSwing(IUIContext uiContext) {
super(uiContext);
}
////////////////////////////////////////////////////////////////////////////
//
// IUIThreadMonitor Accessors
//
// //////////////////////////////////////////////////////////////////////////
/**
* Add event listeners to monitor events being processed by the UI.
*/
protected void addEventListeners() {
Toolkit.getDefaultToolkit().addAWTEventListener(_awtEventListener, EVENT_TYPES);
}
/**
* Remove the event listeners added to monitor events being processed by the UI.
*/
protected void removeEventListeners() {
Toolkit.getDefaultToolkit().removeAWTEventListener(_awtEventListener);
}
/**
* Determine if the test has ended.
*
* @return <code>true</code> if test has ended, else <code>false</code>
*/
protected boolean hasTestEnded() {
return getListener() == null;
}
/**
* Wait for up to one second to determine if the user interface thread is responsive
* and processing new events.
*
* @return <code>true</code> if the user interface thread is responsive, or
* <code>false</code> if it has not processed any new events within the last
* one second
*/
protected boolean isUIThreadResponsive() {
synchronized (_lock) {
_uiThreadResponsive = false;
}
SwingUtilities.invokeLater(_threadResponsiveRunnable);
for (int i = 0; i < 100; i++) {
boolean b;
b = wasUIThreadResponsive();
if (b)
break;
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
// ignored
}
}
synchronized (_lock) {
return _uiThreadResponsive;
}
}
protected boolean wasUIThreadResponsive() {
boolean b;
synchronized (_lock) {
b = _uiThreadResponsive;
}
return b;
}
}