/*******************************************************************************
* Copyright (c) 2011 Tasktop Technologies and others.
* 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.commons.activity.ui;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.mylyn.commons.activity.ui.UserActivityListener;
import org.eclipse.mylyn.commons.activity.ui.spi.AbstractUserActivityMonitor;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.osgi.util.NLS;
/**
* Monitors user activity and notifies listeners.
*
* @author Steffen Pingel
*/
public class UserActivityManager implements IUserActivityManager {
private final Set<UserActivityListener> activityListeners;
private final List<AbstractUserActivityMonitor> activityMonitors;
private final MonitorUserActivityJob monitorJob;
public UserActivityManager(List<AbstractUserActivityMonitor> monitors) {
this.activityListeners = new CopyOnWriteArraySet<UserActivityListener>();
this.activityMonitors = new CopyOnWriteArrayList<AbstractUserActivityMonitor>(monitors);
this.monitorJob = createMonitorActivityJob();
}
public void addAttentionListener(UserActivityListener listener) {
activityListeners.add(listener);
}
public int getInactivityTimeout() {
return monitorJob.getInactivityTimeout();
}
public long getLastInteractionTime() {
for (final AbstractUserActivityMonitor monitor : activityMonitors) {
final boolean[] success = new boolean[1];
final long[] result = new long[1];
SafeRunner.run(new ISafeRunnable() {
public void handleException(Throwable e) {
disableFailedMonitor(monitor, e);
}
public void run() throws Exception {
if (monitor.isEnabled()) {
result[0] = monitor.getLastInteractionTime();
success[0] = true;
}
}
});
if (success[0]) {
return result[0];
}
}
return -1;
}
/**
* Returns true, if other activity monitors than {@link WorkbenchUserActivityMonitor} have been registered.
*/
public boolean isTrackingOsTime() {
return activityMonitors.size() > 1;
}
public void removeAttentionListener(UserActivityListener listener) {
activityListeners.remove(listener);
}
public void setInactivityTimeout(int inactivityTimeout) {
monitorJob.setInactivityTimeout(inactivityTimeout);
}
public void start() {
for (final AbstractUserActivityMonitor monitor : activityMonitors) {
SafeRunner.run(new ISafeRunnable() {
public void handleException(Throwable e) {
disableFailedMonitor(monitor, e);
}
public void run() throws Exception {
monitor.start();
}
});
}
monitorJob.reschedule();
}
public void stop() {
monitorJob.cancel();
for (final AbstractUserActivityMonitor monitor : activityMonitors) {
SafeRunner.run(new ISafeRunnable() {
public void handleException(Throwable e) {
disableFailedMonitor(monitor, e);
}
public void run() throws Exception {
monitor.stop();
}
});
}
}
private MonitorUserActivityJob createMonitorActivityJob() {
MonitorUserActivityJob job = new MonitorUserActivityJob(new IUserActivityManagerCallback() {
public void active() {
UserActivityManager.this.fireActive();
}
public void addMonitoredActivityTime(long localStartTime, long currentTime) {
UserActivityManager.this.fireMonitoredActivityTime(localStartTime, currentTime);
}
public long getLastEventTime() {
return UserActivityManager.this.getLastInteractionTime();
}
public void inactive() {
UserActivityManager.this.fireInactive();
}
});
job.setSystem(true);
job.setPriority(Job.INTERACTIVE);
return job;
}
private void disableFailedMonitor(AbstractUserActivityMonitor monitor, Throwable e) {
StatusHandler.log(new Status(IStatus.WARNING, IActivityUiConstants.ID_PLUGIN, NLS.bind(
"Activity monitor ''{0}'' was disabled due to a failure", monitor.getClass()), e)); //$NON-NLS-1$
activityMonitors.remove(monitor);
}
private void fireActive() {
for (UserActivityListener attentionListener : activityListeners) {
attentionListener.userAttentionGained();
}
}
private void fireInactive() {
for (UserActivityListener attentionListener : activityListeners) {
attentionListener.userAttentionLost();
}
}
/**
* Invoked when activity is recorded.
*
* @param start
* time in milliseconds when user activity started
* @param end
* time in milliseconds when user activity ended
*/
private void fireMonitoredActivityTime(long start, long end) {
for (UserActivityListener attentionListener : activityListeners) {
attentionListener.userActive(start, end);
}
}
void init(List<AbstractUserActivityMonitor> monitors) {
this.activityMonitors.addAll(monitors);
}
}