NEW - bug 292466: background synchronization stops if active synchronization is canceled
https://bugs.eclipse.org/bugs/show_bug.cgi?id=292466
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java
index 0be919c..2c9dd15 100644
--- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java
+++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java
@@ -69,43 +69,50 @@
 
 	@Override
 	protected IStatus run(IProgressMonitor jobMonitor) {
-		monitor.attach(jobMonitor);
 		try {
-			monitor.beginTask(Messages.SubmitTaskJob_Submitting_task, 2 * (1 + getSubmitJobListeners().length) * 100);
+			monitor.setCanceled(false);
+			monitor.attach(jobMonitor);
+			try {
+				monitor.beginTask(Messages.SubmitTaskJob_Submitting_task,
+						2 * (1 + getSubmitJobListeners().length) * 100);
 
-			// post task data
-			AbstractTaskDataHandler taskDataHandler = connector.getTaskDataHandler();
-			monitor.subTask(Messages.SubmitTaskJob_Sending_data);
-			response = taskDataHandler.postTaskData(taskRepository, taskData, oldAttributes, Policy.subMonitorFor(
-					monitor, 100));
-			if (response == null || response.getTaskId() == null) {
-				throw new CoreException(new RepositoryStatus(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN,
-						RepositoryStatus.ERROR_INTERNAL,
-						"Task could not be created. No additional information was provided by the connector.")); //$NON-NLS-1$
+				// post task data
+				AbstractTaskDataHandler taskDataHandler = connector.getTaskDataHandler();
+				monitor.subTask(Messages.SubmitTaskJob_Sending_data);
+				response = taskDataHandler.postTaskData(taskRepository, taskData, oldAttributes, Policy.subMonitorFor(
+						monitor, 100));
+				if (response == null || response.getTaskId() == null) {
+					throw new CoreException(new RepositoryStatus(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN,
+							RepositoryStatus.ERROR_INTERNAL,
+							"Task could not be created. No additional information was provided by the connector.")); //$NON-NLS-1$
+				}
+				fireTaskSubmitted(monitor);
+
+				// update task in task list
+				String taskId = response.getTaskId();
+				monitor.subTask(Messages.SubmitTaskJob_Receiving_data);
+				TaskData updatedTaskData = connector.getTaskData(taskRepository, taskId, Policy.subMonitorFor(monitor,
+						100));
+				task = createTask(monitor, updatedTaskData);
+				taskDataManager.putSubmittedTaskData(task, updatedTaskData);
+				fireTaskSynchronized(monitor);
+			} catch (CoreException e) {
+				errorStatus = e.getStatus();
+			} catch (OperationCanceledException e) {
+				errorStatus = Status.CANCEL_STATUS;
+			} catch (Exception e) {
+				StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN,
+						"Unexpected error during task submission", e)); //$NON-NLS-1$
+				errorStatus = new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Unexpected error: " //$NON-NLS-1$
+						+ e.getMessage(), e);
+			} finally {
+				monitor.done();
 			}
-			fireTaskSubmitted(monitor);
-
-			// update task in task list
-			String taskId = response.getTaskId();
-			monitor.subTask(Messages.SubmitTaskJob_Receiving_data);
-			TaskData updatedTaskData = connector.getTaskData(taskRepository, taskId, Policy.subMonitorFor(monitor, 100));
-			task = createTask(monitor, updatedTaskData);
-			taskDataManager.putSubmittedTaskData(task, updatedTaskData);
-			fireTaskSynchronized(monitor);
-		} catch (CoreException e) {
-			errorStatus = e.getStatus();
-		} catch (OperationCanceledException e) {
-			errorStatus = Status.CANCEL_STATUS;
-		} catch (Exception e) {
-			StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN,
-					"Unexpected error during task submission", e)); //$NON-NLS-1$
-			errorStatus = new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Unexpected error: " //$NON-NLS-1$
-					+ e.getMessage(), e);
+			fireDone();
+			return (errorStatus == Status.CANCEL_STATUS) ? Status.CANCEL_STATUS : Status.OK_STATUS;
 		} finally {
-			monitor.done();
+			monitor.detach(jobMonitor);
 		}
-		fireDone();
-		return (errorStatus == Status.CANCEL_STATUS) ? Status.CANCEL_STATUS : Status.OK_STATUS;
 	}
 
 	private ITask createTask(IProgressMonitor monitor, TaskData updatedTaskData) throws CoreException {
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeQueriesJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeQueriesJob.java
index 7827423..8e15390 100644
--- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeQueriesJob.java
+++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeQueriesJob.java
@@ -148,109 +148,114 @@
 
 	@Override
 	public IStatus run(IProgressMonitor jobMonitor) {
-		monitor.attach(jobMonitor);
 		try {
-			monitor.beginTask(Messages.SynchronizeQueriesJob_Processing, 20 + queries.size() * 20 + 40 + 10);
-
-			Set<ITask> allTasks;
-			if (!isFullSynchronization()) {
-				allTasks = new HashSet<ITask>();
-				for (RepositoryQuery query : queries) {
-					allTasks.addAll(query.getChildren());
-				}
-			} else {
-				allTasks = taskList.getTasks(repository.getRepositoryUrl());
-			}
-
-			ObjectSchedulingRule rule = new ObjectSchedulingRule(repository);
+			monitor.setCanceled(false);
+			monitor.attach(jobMonitor);
 			try {
-				Job.getJobManager().beginRule(rule, monitor);
+				monitor.beginTask(Messages.SynchronizeQueriesJob_Processing, 20 + queries.size() * 20 + 40 + 10);
 
-				final Map<String, TaskRelation[]> relationsByTaskId = new HashMap<String, TaskRelation[]>();
-				SynchronizationSession session = new SynchronizationSession(taskDataManager) {
-					@Override
-					public void putTaskData(ITask task, TaskData taskData) throws CoreException {
-						boolean changed = connector.hasTaskChanged(repository, task, taskData);
-						taskDataManager.putUpdatedTaskData(task, taskData, isUser(), this);
-						if (taskData.isPartial()) {
-							if (changed && connector.canSynchronizeTask(repository, task)) {
-								markStale(task);
-							}
-						} else {
-							Collection<TaskRelation> relations = connector.getTaskRelations(taskData);
-							if (relations != null) {
-								relationsByTaskId.put(task.getTaskId(), relations.toArray(new TaskRelation[0]));
+				Set<ITask> allTasks;
+				if (!isFullSynchronization()) {
+					allTasks = new HashSet<ITask>();
+					for (RepositoryQuery query : queries) {
+						allTasks.addAll(query.getChildren());
+					}
+				} else {
+					allTasks = taskList.getTasks(repository.getRepositoryUrl());
+				}
+
+				ObjectSchedulingRule rule = new ObjectSchedulingRule(repository);
+				try {
+					Job.getJobManager().beginRule(rule, monitor);
+
+					final Map<String, TaskRelation[]> relationsByTaskId = new HashMap<String, TaskRelation[]>();
+					SynchronizationSession session = new SynchronizationSession(taskDataManager) {
+						@Override
+						public void putTaskData(ITask task, TaskData taskData) throws CoreException {
+							boolean changed = connector.hasTaskChanged(repository, task, taskData);
+							taskDataManager.putUpdatedTaskData(task, taskData, isUser(), this);
+							if (taskData.isPartial()) {
+								if (changed && connector.canSynchronizeTask(repository, task)) {
+									markStale(task);
+								}
+							} else {
+								Collection<TaskRelation> relations = connector.getTaskRelations(taskData);
+								if (relations != null) {
+									relationsByTaskId.put(task.getTaskId(), relations.toArray(new TaskRelation[0]));
+								}
 							}
 						}
-					}
-				};
-				session.setTaskRepository(repository);
-				session.setFullSynchronization(isFullSynchronization());
-				session.setTasks(Collections.unmodifiableSet(allTasks));
-				session.setNeedsPerformQueries(true);
-				session.setUser(isUser());
+					};
+					session.setTaskRepository(repository);
+					session.setFullSynchronization(isFullSynchronization());
+					session.setTasks(Collections.unmodifiableSet(allTasks));
+					session.setNeedsPerformQueries(true);
+					session.setUser(isUser());
 
-				updateQueryStatus(null);
-				try {
-					boolean success = preSynchronization(session, new SubProgressMonitor(monitor, 20));
+					updateQueryStatus(null);
+					try {
+						boolean success = preSynchronization(session, new SubProgressMonitor(monitor, 20));
 
-					if ((success && session.needsPerformQueries()) || isUser()) {
-						// synchronize queries, tasks changed within query are added to set of tasks to be synchronized
-						synchronizeQueries(monitor, session);
-					} else {
-						monitor.worked(queries.size() * 20);
+						if ((success && session.needsPerformQueries()) || isUser()) {
+							// synchronize queries, tasks changed within query are added to set of tasks to be synchronized
+							synchronizeQueries(monitor, session);
+						} else {
+							monitor.worked(queries.size() * 20);
+						}
+					} finally {
+						for (RepositoryQuery repositoryQuery : queries) {
+							repositoryQuery.setSynchronizing(false);
+						}
+						taskList.notifySynchronizationStateChanged(queries);
 					}
+
+					Set<ITask> tasksToBeSynchronized = new HashSet<ITask>();
+					for (ITask task : session.getStaleTasks()) {
+						tasksToBeSynchronized.add(task);
+						((AbstractTask) task).setSynchronizing(true);
+					}
+
+					// synchronize tasks that were marked by the connector
+					SynchronizeTasksJob job = new SynchronizeTasksJob(taskList, taskDataManager, tasksModel, connector,
+							repository, tasksToBeSynchronized);
+					job.setUser(isUser());
+					job.setSession(session);
+					if (!tasksToBeSynchronized.isEmpty()) {
+						Policy.checkCanceled(monitor);
+						IStatus result = job.run(new SubProgressMonitor(monitor, 30));
+						if (result == Status.CANCEL_STATUS) {
+							throw new OperationCanceledException();
+						}
+						statuses.addAll(job.getStatuses());
+					}
+					monitor.subTask(Messages.SynchronizeQueriesJob_Receiving_related_tasks);
+					job.synchronizedTaskRelations(monitor, relationsByTaskId);
+					monitor.worked(10);
+
+					session.setChangedTasks(tasksToBeSynchronized);
+					if (statuses.size() > 0) {
+						Status status = new MultiStatus(ITasksCoreConstants.ID_PLUGIN, 0,
+								statuses.toArray(new IStatus[0]), "Query synchronization failed", null); //$NON-NLS-1$
+						session.setStatus(status);
+					}
+
+					// hook into the connector for synchronization time stamp management
+					postSynchronization(session, new SubProgressMonitor(monitor, 10));
 				} finally {
-					for (RepositoryQuery repositoryQuery : queries) {
-						repositoryQuery.setSynchronizing(false);
-					}
-					taskList.notifySynchronizationStateChanged(queries);
+					Job.getJobManager().endRule(rule);
 				}
-
-				Set<ITask> tasksToBeSynchronized = new HashSet<ITask>();
-				for (ITask task : session.getStaleTasks()) {
-					tasksToBeSynchronized.add(task);
-					((AbstractTask) task).setSynchronizing(true);
-				}
-
-				// synchronize tasks that were marked by the connector
-				SynchronizeTasksJob job = new SynchronizeTasksJob(taskList, taskDataManager, tasksModel, connector,
-						repository, tasksToBeSynchronized);
-				job.setUser(isUser());
-				job.setSession(session);
-				if (!tasksToBeSynchronized.isEmpty()) {
-					Policy.checkCanceled(monitor);
-					IStatus result = job.run(new SubProgressMonitor(monitor, 30));
-					if (result == Status.CANCEL_STATUS) {
-						throw new OperationCanceledException();
-					}
-					statuses.addAll(job.getStatuses());
-				}
-				monitor.subTask(Messages.SynchronizeQueriesJob_Receiving_related_tasks);
-				job.synchronizedTaskRelations(monitor, relationsByTaskId);
-				monitor.worked(10);
-
-				session.setChangedTasks(tasksToBeSynchronized);
-				if (statuses.size() > 0) {
-					Status status = new MultiStatus(ITasksCoreConstants.ID_PLUGIN, 0, statuses.toArray(new IStatus[0]),
-							"Query synchronization failed", null); //$NON-NLS-1$
-					session.setStatus(status);
-				}
-
-				// hook into the connector for synchronization time stamp management
-				postSynchronization(session, new SubProgressMonitor(monitor, 10));
+			} catch (OperationCanceledException e) {
+				return Status.CANCEL_STATUS;
+			} catch (Exception e) {
+				StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Synchronization failed", e)); //$NON-NLS-1$
+			} catch (LinkageError e) {
+				StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, NLS.bind(
+						"Synchronization for connector ''{0}'' failed", connector.getConnectorKind()), e)); //$NON-NLS-1$
 			} finally {
-				Job.getJobManager().endRule(rule);
+				monitor.done();
 			}
-		} catch (OperationCanceledException e) {
-			return Status.CANCEL_STATUS;
-		} catch (Exception e) {
-			StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Synchronization failed", e)); //$NON-NLS-1$
-		} catch (LinkageError e) {
-			StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, NLS.bind(
-					"Synchronization for connector ''{0}'' failed", connector.getConnectorKind()), e)); //$NON-NLS-1$
 		} finally {
-			monitor.done();
+			monitor.detach(jobMonitor);
 		}
 		return Status.OK_STATUS;
 	}
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeRepositoriesJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeRepositoriesJob.java
index 03444db..163b17f 100644
--- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeRepositoriesJob.java
+++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeRepositoriesJob.java
@@ -81,69 +81,75 @@
 
 	@Override
 	public IStatus run(IProgressMonitor jobMonitor) {
-		monitor.attach(jobMonitor);
-		// get the current list of repositories
-		Set<TaskRepository> repositories = this.repositories;
-		if (repositories == null) {
-			repositories = new HashSet<TaskRepository>(repositoryManager.getAllRepositories());
-		}
 		try {
-			monitor.beginTask(Messages.SynchronizeRepositoriesJob_Processing, repositories.size() * 100);
+			monitor.setCanceled(false);
+			monitor.attach(jobMonitor);
 
-			if (TRACE_ENABLED) {
-				trace("Starting repository synchronization"); //$NON-NLS-1$
+			// get the current list of repositories
+			Set<TaskRepository> repositories = this.repositories;
+			if (repositories == null) {
+				repositories = new HashSet<TaskRepository>(repositoryManager.getAllRepositories());
 			}
-			for (TaskRepository repository : repositories) {
-				if (monitor.isCanceled()) {
-					return Status.CANCEL_STATUS;
-				}
-
-				if (repository.isOffline()) {
-					if (TRACE_ENABLED) {
-						trace("Skipping synchronization for " + repository.getRepositoryLabel()); //$NON-NLS-1$
-					}
-					monitor.worked(100);
-					continue;
-				}
-
-				monitor.setTaskName(MessageFormat.format(Messages.SynchronizeRepositoriesJob_Processing_,
-						repository.getRepositoryLabel()));
-
-				final AbstractRepositoryConnector connector = repositoryManager.getRepositoryConnector(repository.getConnectorKind());
-				Set<RepositoryQuery> queries = new HashSet<RepositoryQuery>(
-						taskList.getRepositoryQueries(repository.getRepositoryUrl()));
-				// remove queries that are not configured for auto update
-				if (!isUser()) {
-					for (Iterator<RepositoryQuery> it = queries.iterator(); it.hasNext();) {
-						if (!it.next().getAutoUpdate()) {
-							it.remove();
-						}
-					}
-				}
-
-				if (isUser() || queries.isEmpty()) {
-					monitor.worked(20);
-				} else {
-					// occasionally request update of repository configuration attributes as part of background synchronizations
-					updateRepositoryConfiguration(repository, connector, new SubProgressMonitor(monitor, 20));
-				}
+			try {
+				monitor.beginTask(Messages.SynchronizeRepositoriesJob_Processing, repositories.size() * 100);
 
 				if (TRACE_ENABLED) {
-					trace("Synchronizing queries for " + repository.getRepositoryLabel()); //$NON-NLS-1$
+					trace("Starting repository synchronization"); //$NON-NLS-1$
 				}
-				updateQueries(repository, connector, queries, monitor);
-			}
-			if (TRACE_ENABLED) {
-				trace("Completed repository synchronization"); //$NON-NLS-1$
-			}
-			// it's better to remove the job from the progress view instead of having it blocked until all child jobs finish
+				for (TaskRepository repository : repositories) {
+					if (monitor.isCanceled()) {
+						return Status.CANCEL_STATUS;
+					}
+
+					if (repository.isOffline()) {
+						if (TRACE_ENABLED) {
+							trace("Skipping synchronization for " + repository.getRepositoryLabel()); //$NON-NLS-1$
+						}
+						monitor.worked(100);
+						continue;
+					}
+
+					monitor.setTaskName(MessageFormat.format(Messages.SynchronizeRepositoriesJob_Processing_,
+							repository.getRepositoryLabel()));
+
+					final AbstractRepositoryConnector connector = repositoryManager.getRepositoryConnector(repository.getConnectorKind());
+					Set<RepositoryQuery> queries = new HashSet<RepositoryQuery>(
+							taskList.getRepositoryQueries(repository.getRepositoryUrl()));
+					// remove queries that are not configured for auto update
+					if (!isUser()) {
+						for (Iterator<RepositoryQuery> it = queries.iterator(); it.hasNext();) {
+							if (!it.next().getAutoUpdate()) {
+								it.remove();
+							}
+						}
+					}
+
+					if (isUser() || queries.isEmpty()) {
+						monitor.worked(20);
+					} else {
+						// occasionally request update of repository configuration attributes as part of background synchronizations
+						updateRepositoryConfiguration(repository, connector, new SubProgressMonitor(monitor, 20));
+					}
+
+					if (TRACE_ENABLED) {
+						trace("Synchronizing queries for " + repository.getRepositoryLabel()); //$NON-NLS-1$
+					}
+					updateQueries(repository, connector, queries, monitor);
+				}
+				if (TRACE_ENABLED) {
+					trace("Completed repository synchronization"); //$NON-NLS-1$
+				}
+				// it's better to remove the job from the progress view instead of having it blocked until all child jobs finish
 //			if (isUser()) {
 //				Job.getJobManager().join(family, monitor);
 //			}
-		} catch (OperationCanceledException e) {
-			return Status.CANCEL_STATUS;
+			} catch (OperationCanceledException e) {
+				return Status.CANCEL_STATUS;
+			} finally {
+				monitor.done();
+			}
 		} finally {
-			monitor.done();
+			monitor.detach(jobMonitor);
 		}
 		return Status.OK_STATUS;
 	}
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeTasksJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeTasksJob.java
index c6482d5..1bdf43b 100644
--- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeTasksJob.java
+++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SynchronizeTasksJob.java
@@ -100,43 +100,48 @@
 
 	@Override
 	public IStatus run(IProgressMonitor jobMonitor) {
-		monitor.attach(jobMonitor);
 		try {
-			if (taskRepository == null) {
-				try {
-					monitor.beginTask(Messages.SynchronizeTasksJob_Processing, allTasks.size() * 100);
-					// group tasks by repository
-					Map<TaskRepository, Set<ITask>> tasksByRepository = new HashMap<TaskRepository, Set<ITask>>();
-					for (ITask task : allTasks) {
-						TaskRepository repository = repositoryManager.getRepository(task.getConnectorKind(),
-								task.getRepositoryUrl());
-						Set<ITask> tasks = tasksByRepository.get(repository);
-						if (tasks == null) {
-							tasks = new HashSet<ITask>();
-							tasksByRepository.put(repository, tasks);
+			monitor.setCanceled(false);
+			monitor.attach(jobMonitor);
+			try {
+				if (taskRepository == null) {
+					try {
+						monitor.beginTask(Messages.SynchronizeTasksJob_Processing, allTasks.size() * 100);
+						// group tasks by repository
+						Map<TaskRepository, Set<ITask>> tasksByRepository = new HashMap<TaskRepository, Set<ITask>>();
+						for (ITask task : allTasks) {
+							TaskRepository repository = repositoryManager.getRepository(task.getConnectorKind(),
+									task.getRepositoryUrl());
+							Set<ITask> tasks = tasksByRepository.get(repository);
+							if (tasks == null) {
+								tasks = new HashSet<ITask>();
+								tasksByRepository.put(repository, tasks);
+							}
+							tasks.add(task);
 						}
-						tasks.add(task);
+						// synchronize tasks for each repositories
+						for (TaskRepository taskRepository : tasksByRepository.keySet()) {
+							setName(MessageFormat.format(Messages.SynchronizeTasksJob_Synchronizing_Tasks__X_,
+									taskRepository.getRepositoryLabel()));
+							this.taskRepository = taskRepository;
+							Set<ITask> repositoryTasks = tasksByRepository.get(taskRepository);
+							run(repositoryTasks, new SubProgressMonitor(monitor, repositoryTasks.size() * 100));
+						}
+					} finally {
+						monitor.done();
 					}
-					// synchronize tasks for each repositories
-					for (TaskRepository taskRepository : tasksByRepository.keySet()) {
-						setName(MessageFormat.format(Messages.SynchronizeTasksJob_Synchronizing_Tasks__X_,
-								taskRepository.getRepositoryLabel()));
-						this.taskRepository = taskRepository;
-						Set<ITask> repositoryTasks = tasksByRepository.get(taskRepository);
-						run(repositoryTasks, new SubProgressMonitor(monitor, repositoryTasks.size() * 100));
-					}
-				} finally {
-					monitor.done();
+				} else {
+					run(allTasks, monitor);
 				}
-			} else {
-				run(allTasks, monitor);
+			} catch (OperationCanceledException e) {
+				for (ITask task : allTasks) {
+					((AbstractTask) task).setSynchronizing(false);
+					taskList.notifyElementChanged(task);
+				}
+				return Status.CANCEL_STATUS;
 			}
-		} catch (OperationCanceledException e) {
-			for (ITask task : allTasks) {
-				((AbstractTask) task).setSynchronizing(false);
-				taskList.notifyElementChanged(task);
-			}
-			return Status.CANCEL_STATUS;
+		} finally {
+			monitor.detach(jobMonitor);
 		}
 		return Status.OK_STATUS;
 	}
diff --git a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java
index d825736..8bbaffe 100644
--- a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java
+++ b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java
@@ -22,6 +22,7 @@
 import org.eclipse.mylyn.tasks.tests.ui.RetrieveTitleFromUrlTest;
 import org.eclipse.mylyn.tasks.tests.ui.TaskAttachmentPropertyTesterTest;
 import org.eclipse.mylyn.tasks.tests.ui.TaskHyperlinkDetectorTest;
+import org.eclipse.mylyn.tasks.tests.ui.TaskListSynchronizationSchedulerTest;
 import org.eclipse.mylyn.tasks.tests.ui.TaskRelationHyperlinkDetectorTest;
 import org.eclipse.mylyn.tasks.tests.ui.editor.EditorUtilTest;
 import org.eclipse.mylyn.tasks.tests.ui.editor.TaskEditorPartDescriptorTest;
@@ -92,6 +93,7 @@
 		suite.addTestSuite(RetrieveTitleFromUrlTest.class);
 		suite.addTestSuite(EditorUtilTest.class);
 		suite.addTestSuite(FileTaskAttachmentSourceTest.class);
+		suite.addTestSuite(TaskListSynchronizationSchedulerTest.class);
 
 		// XXX long running tests, put back?
 		//suite.addTestSuite(TaskDataImportTest.class);
diff --git a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/TaskListSynchronizationSchedulerTest.java b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/TaskListSynchronizationSchedulerTest.java
new file mode 100644
index 0000000..5bce51c
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/TaskListSynchronizationSchedulerTest.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.tasks.tests.ui;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.mylyn.internal.tasks.ui.ITasksUiPreferenceConstants;
+import org.eclipse.mylyn.internal.tasks.ui.TaskListSynchronizationScheduler;
+import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession;
+import org.eclipse.mylyn.tasks.tests.TaskTestUtil;
+import org.eclipse.mylyn.tasks.tests.connector.MockRepositoryConnector;
+
+/**
+ * @author Steffen Pingel
+ */
+public class TaskListSynchronizationSchedulerTest extends TestCase {
+
+	private class TestConnector extends MockRepositoryConnector {
+
+		CountDownLatch latch = new CountDownLatch(1);
+
+		Throwable e;
+
+		@Override
+		public void preSynchronization(ISynchronizationSession event, IProgressMonitor monitor) throws CoreException {
+			latch.countDown();
+			try {
+				if (!mainLatch.await(10, TimeUnit.SECONDS)) {
+					this.e = new AssertionFailedError("Timed out waiting for main latch");
+				}
+			} catch (InterruptedException e) {
+				this.e = e;
+			}
+		}
+
+		public void reset() {
+			latch = new CountDownLatch(1);
+		}
+
+	}
+
+	private TaskRepository repository;
+
+	private TestConnector connector;
+
+	private AbstractRepositoryConnector oldConnector;
+
+	private final CountDownLatch mainLatch = new CountDownLatch(1);
+
+	@Override
+	protected void setUp() throws Exception {
+		TasksUiPlugin.getDefault().getPreferenceStore().setValue(
+				ITasksUiPreferenceConstants.REPOSITORY_SYNCH_SCHEDULE_ENABLED, false);
+
+		TaskTestUtil.resetTaskListAndRepositories();
+		repository = TaskTestUtil.createMockRepository();
+		TasksUiPlugin.getRepositoryManager().addRepository(repository);
+
+		oldConnector = TasksUiPlugin.getRepositoryManager().removeRepositoryConnector(repository.getConnectorKind());
+		connector = new TestConnector();
+		TasksUiPlugin.getRepositoryManager().addRepositoryConnector(connector);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		release();
+		TasksUiPlugin.getRepositoryManager().removeRepositoryConnector(repository.getConnectorKind());
+		TasksUiPlugin.getRepositoryManager().addRepositoryConnector(oldConnector);
+	}
+
+	public void testSynchronization() throws Exception {
+		TaskListSynchronizationScheduler scheduler = new TaskListSynchronizationScheduler(
+				TasksUiPlugin.getTaskJobFactory());
+		scheduler.setInterval(1);
+		assertTrue(connector.latch.await(10, TimeUnit.SECONDS));
+
+		// cancel and reschedule
+		scheduler.userAttentionLost();
+		scheduler.userAttentionGained();
+		release();
+
+		assertTrue("Expected synchronization to run again", connector.latch.await(5, TimeUnit.SECONDS));
+	}
+
+	private void release() throws Exception {
+		if (connector.e instanceof Error) {
+			throw (Error) connector.e;
+		}
+		if (connector.e instanceof Exception) {
+			throw (Exception) connector.e;
+		}
+		connector.reset();
+		mainLatch.countDown();
+	}
+
+}