From 24d90aa0204eae5cfe075f453942a88c84901ea7 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Thu, 15 Jul 2010 03:43:42 -0700 Subject: [PATCH] Deleted old sync stuff --- .../astrid/activities/SyncPreferences.java | 5 +- .../timsu/astrid/data/sync/SyncMapping.java | 9 +- .../astrid/data/task/TaskController.java | 14 +- .../timsu/astrid/sync/RTMSyncProvider.java | 606 ---------------- .../astrid/sync/SynchronizationProvider.java | 684 ------------------ .../astrid/sync/SynchronizationService.java | 149 ---- .../com/timsu/astrid/sync/Synchronizer.java | 292 -------- .../com/timsu/astrid/sync/TaskProxy.java | 219 ------ 8 files changed, 12 insertions(+), 1966 deletions(-) delete mode 100644 astrid/src-legacy/com/timsu/astrid/sync/RTMSyncProvider.java delete mode 100644 astrid/src-legacy/com/timsu/astrid/sync/SynchronizationProvider.java delete mode 100644 astrid/src-legacy/com/timsu/astrid/sync/SynchronizationService.java delete mode 100644 astrid/src-legacy/com/timsu/astrid/sync/Synchronizer.java delete mode 100644 astrid/src-legacy/com/timsu/astrid/sync/TaskProxy.java diff --git a/astrid/src-legacy/com/timsu/astrid/activities/SyncPreferences.java b/astrid/src-legacy/com/timsu/astrid/activities/SyncPreferences.java index a820e36ca..aa04880e4 100644 --- a/astrid/src-legacy/com/timsu/astrid/activities/SyncPreferences.java +++ b/astrid/src-legacy/com/timsu/astrid/activities/SyncPreferences.java @@ -27,8 +27,8 @@ import android.content.DialogInterface; import android.content.res.Resources; import android.os.Bundle; import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceActivity; +import android.preference.Preference.OnPreferenceChangeListener; import android.view.KeyEvent; import android.view.View; import android.widget.Button; @@ -36,7 +36,6 @@ import android.widget.TextView; import com.flurry.android.FlurryAgent; import com.timsu.astrid.R; -import com.timsu.astrid.sync.Synchronizer; import com.timsu.astrid.utilities.Constants; import com.timsu.astrid.utilities.DialogUtilities; import com.timsu.astrid.utilities.Preferences; @@ -91,7 +90,7 @@ public class SyncPreferences extends PreferenceActivity { new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - Synchronizer.clearUserData(SyncPreferences.this); +// Synchronizer.clearUserData(SyncPreferences.this); // force a synchronization if sync preference is still set oldRtmSyncPreference = false; } diff --git a/astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java b/astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java index f0a47f6c5..5959768c7 100644 --- a/astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java +++ b/astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java @@ -29,7 +29,6 @@ import android.util.Log; import com.timsu.astrid.data.AbstractController; import com.timsu.astrid.data.AbstractModel; import com.timsu.astrid.data.task.TaskIdentifier; -import com.timsu.astrid.sync.TaskProxy; import com.timsu.astrid.utilities.DialogUtilities; @@ -109,10 +108,10 @@ public class SyncMapping extends AbstractModel { // --- constructor pass-through - - public SyncMapping(TaskIdentifier task, TaskProxy taskProxy) { - this(task, taskProxy.getSyncServiceId(), taskProxy.getRemoteId()); - } +// +// public SyncMapping(TaskIdentifier task, TaskProxy taskProxy) { +// this(task, taskProxy.getSyncServiceId(), taskProxy.getRemoteId()); +// } public SyncMapping(TaskIdentifier task, int syncServiceId, String remoteId) { super(); diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java index 178c8e8ef..62e290677 100644 --- a/astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java @@ -42,8 +42,6 @@ import com.timsu.astrid.data.sync.SyncDataController; import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo; import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper; import com.timsu.astrid.provider.TasksProvider; -import com.timsu.astrid.sync.Synchronizer; -import com.timsu.astrid.sync.Synchronizer.SynchronizerListener; import com.todoroo.astrid.widget.TasksWidget.UpdateService; /** @@ -373,12 +371,12 @@ public class TaskController extends AbstractController { // handle sync-on-complete if((model.getFlags() & TaskModelForHandlers.FLAG_SYNC_ON_COMPLETE) > 0 && !duringSync) { - Synchronizer synchronizer = new Synchronizer(model.getTaskIdentifier()); - synchronizer.synchronize(context, new SynchronizerListener() { - public void onSynchronizerFinished(int numServicesSynced) { -// TaskListSubActivity.shouldRefreshTaskList = true; - } - }); +// Synchronizer synchronizer = new Synchronizer(model.getTaskIdentifier()); +// synchronizer.synchronize(context, new SynchronizerListener() { +// public void onSynchronizerFinished(int numServicesSynced) { +//// TaskListSubActivity.shouldRefreshTaskList = true; +// } +// }); } cursor.close(); diff --git a/astrid/src-legacy/com/timsu/astrid/sync/RTMSyncProvider.java b/astrid/src-legacy/com/timsu/astrid/sync/RTMSyncProvider.java deleted file mode 100644 index 3e9b59351..000000000 --- a/astrid/src-legacy/com/timsu/astrid/sync/RTMSyncProvider.java +++ /dev/null @@ -1,606 +0,0 @@ -/* - * ASTRID: Android's Simple Task Recording Dashboard - * - * Copyright (c) 2009 Tim Su - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.timsu.astrid.sync; - -import java.io.IOException; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.Map.Entry; - -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.os.Handler; -import android.util.Log; - -import com.flurry.android.FlurryAgent; -import com.mdt.rtm.ApplicationInfo; -import com.mdt.rtm.ServiceException; -import com.mdt.rtm.ServiceImpl; -import com.mdt.rtm.ServiceInternalException; -import com.mdt.rtm.data.RtmList; -import com.mdt.rtm.data.RtmLists; -import com.mdt.rtm.data.RtmTask; -import com.mdt.rtm.data.RtmTaskList; -import com.mdt.rtm.data.RtmTaskNote; -import com.mdt.rtm.data.RtmTaskSeries; -import com.mdt.rtm.data.RtmTasks; -import com.mdt.rtm.data.RtmAuth.Perms; -import com.mdt.rtm.data.RtmTask.Priority; -import com.timsu.astrid.R; -import com.timsu.astrid.activities.SyncLoginActivity; -import com.timsu.astrid.activities.SyncLoginActivity.SyncLoginCallback; -import com.timsu.astrid.data.enums.Importance; -import com.timsu.astrid.data.sync.SyncMapping; -import com.timsu.astrid.data.tag.TagController; -import com.timsu.astrid.data.tag.TagModelForView; -import com.timsu.astrid.data.task.AbstractTaskModel; -import com.timsu.astrid.data.task.TaskModelForSync; -import com.timsu.astrid.utilities.AstridUtilities; -import com.timsu.astrid.utilities.Preferences; - -public class RTMSyncProvider extends SynchronizationProvider { - - private ServiceImpl rtmService = null; - private String INBOX_LIST_NAME = "Inbox"; - Map listNameToIdMap = new HashMap(); - Map listIdToNameMap = new HashMap(); - - public RTMSyncProvider(int id) { - super(id); - } - - // --- abstract methods - - @Override - String getName() { - return "RTM"; - } - - @Override - protected void synchronize(final Context activity) { - // authenticate the user. this will automatically call the next step - authenticate(activity); - } - - @Override - public void clearPersonalData(Context context) { - Preferences.setSyncRTMToken(context, null); - Preferences.setSyncRTMLastSync(context, null); - synchronizer.getSyncController(context).deleteAllMappings(getId()); - } - - // --- authentication - - /** Helper method that handles RTM methods and may show an error dialog */ - private void handleRtmException(Context context, String tag, Exception e, - boolean showErrorIfNeeded) { - // occurs when application was closed - if(e instanceof IllegalStateException) { - AstridUtilities.reportFlurryError(tag + "-caught", e); - Log.e(tag, "Illegal State during Sync", e); - - // occurs when network error - } else if(e instanceof ServiceInternalException && - ((ServiceInternalException)e).getEnclosedException() instanceof - IOException) { - Exception enclosedException = ((ServiceInternalException)e).getEnclosedException(); - AstridUtilities.reportFlurryError(tag + "-ioexception", enclosedException); - if(showErrorIfNeeded) - showError(context, enclosedException, "Connection Error! Check your " + - "Internet connection & try again..."); - } else { - if(e instanceof ServiceInternalException) - e = ((ServiceInternalException)e).getEnclosedException(); - AstridUtilities.reportFlurryError(tag + "-unhandled", e); - if(showErrorIfNeeded) - showError(context, e, null); - } - } - - /** Perform authentication with RTM. Will open the SyncBrowser if necessary */ - private void authenticate(final Context context) { - final Resources r = context.getResources(); - FlurryAgent.onEvent("rtm-started"); - - try { - String apiKey = "bd9883b3384a21ead17501da38bb1e68"; - String sharedSecret = "a19b2a020345219b"; - String appName = null; - String authToken = Preferences.getSyncRTMToken(context); - - // check if we have a token & it works - if(authToken != null) { - rtmService = new ServiceImpl(new ApplicationInfo( - apiKey, sharedSecret, appName, authToken)); - if(!rtmService.isServiceAuthorized()) // re-do login - authToken = null; - } - - // don't do anything if you're a background service - if(authToken == null && isBackgroundService()) - return; - - if(authToken == null) { - // try completing the authorization if it was partial - if(rtmService != null) { - try { - String token = rtmService.completeAuthorization(); - Log.w("astrid", "got RTM token: " + token); - Preferences.setSyncRTMToken(context, token); - performSync(context); - - return; - } catch (Exception e) { - // didn't work. do the process again. - } - } - - // open up a dialog and have the user go to browser - FlurryAgent.onEvent("rtm-login-dialog"); - - rtmService = new ServiceImpl(new ApplicationInfo( - apiKey, sharedSecret, appName)); - final String url = rtmService.beginAuthorization(Perms.delete); - if(progressDialog != null) - progressDialog.dismiss(); - - Intent intent = new Intent(context, SyncLoginActivity.class); - SyncLoginActivity.setCallback(new SyncLoginCallback() { - @Override - public String verifyLogin(final Handler syncLoginHandler) { - if(rtmService == null) { - Log.e("rtmsync", "Error: sync login activity displayed with no service!"); - return null; - } - - try { - String token = rtmService.completeAuthorization(); - Log.w("astrid", "got RTM token: " + token); - Preferences.setSyncRTMToken(context, token); - return null; - } catch (Exception e) { - // didn't work - AstridUtilities.reportFlurryError("rtm-verify-login", e); - rtmService = null; - if(e instanceof ServiceInternalException) - e = ((ServiceInternalException)e).getEnclosedException(); - - return r.getString(R.string.rtm_login_error) + - " " + e.getMessage(); - } - } - }); - intent.putExtra(SyncLoginActivity.URL_TOKEN, url); - intent.putExtra(SyncLoginActivity.LABEL_TOKEN, R.string.rtm_login_label); - context.startActivity(intent); - - } else { - performSync(context); - } - } catch (IllegalStateException e) { - // occurs when application was closed - Log.e("rtmsync", "Illegal State during Sync", e); - } catch (Exception e) { - handleRtmException(context, "rtm-authenticate", e, true); - } - } - - // --- synchronization! - - private void performSync(final Context context) { - new Thread(new Runnable() { - public void run() { - performSyncInNewThread(context); - } - }).start(); - } - - private void performSyncInNewThread(final Context context) { - try { - postUpdate(new ProgressLabelUpdater(context, R.string.sync_progress_remote)); - postUpdate(new ProgressUpdater(0, 5)); - - // get RTM timeline - final String timeline = rtmService.timelines_create(); - postUpdate(new ProgressUpdater(1, 5)); - - // push task if single task sync is requested - if(getSingleTaskForSync() != null) { - SyncMapping mapping = synchronizer.getSyncController(context). - getSyncMapping(getId(), getSingleTaskForSync()); - if(mapping == null) { - Log.w("astrid-rtm", "Couldn't find sync mapping for updated task"); - return; - } - - TaskProxy localTask = new TaskProxy(getId(), mapping.getRemoteId()); - TaskModelForSync task = synchronizer.getTaskController(context). - fetchTaskForSync(getSingleTaskForSync()); - localTask.readFromTaskModel(task); - postUpdate(new ProgressLabelUpdater(context, R.string.sync_progress_repeating)); - pushLocalTask(timeline, localTask, null, mapping); - } - - // load RTM lists - RtmLists lists = rtmService.lists_getList(); - for(RtmList list : lists.getLists().values()) { - if(list.isSmart() || list.isArchived()) - continue; - listNameToIdMap.put(list.getName().toLowerCase(), list.getId()); - listIdToNameMap.put(list.getId(), list.getName()); - - // read the name of the inbox with the correct case - if(INBOX_LIST_NAME.equalsIgnoreCase(list.getName())) - INBOX_LIST_NAME = list.getName(); - } - postUpdate(new ProgressUpdater(2, 5)); - - // read all tasks - LinkedList remoteChanges = new LinkedList(); - Date lastSyncDate = Preferences.getSyncRTMLastSync(context); - boolean shouldSyncIndividualLists = false; - String filter = null; - if(lastSyncDate == null) - filter = "status:incomplete"; // 1st time sync: get unfinished tasks - - // try the quick synchronization - try { - Thread.sleep(2000); // throttle - postUpdate(new ProgressUpdater(3, 5)); - RtmTasks tasks = rtmService.tasks_getList(null, filter, lastSyncDate); - postUpdate(new ProgressUpdater(5, 5)); - addTasksToList(context, tasks, remoteChanges); - } catch (Exception e) { - handleRtmException(context, "rtm-quick-sync", e, false); - remoteChanges.clear(); - shouldSyncIndividualLists = true; - } - - if(shouldSyncIndividualLists) { - int progress = 0; - for(final Entry entry : listIdToNameMap.entrySet()) { - postUpdate(new ProgressLabelUpdater(context, - R.string.sync_progress_rxlist, entry.getValue())); - postUpdate(new ProgressUpdater(progress++, - listIdToNameMap.size())); - try { - Thread.sleep(1500); - RtmTasks tasks = rtmService.tasks_getList(entry.getKey(), - filter, lastSyncDate); - addTasksToList(context, tasks, remoteChanges); - } catch (Exception e) { - handleRtmException(context, "rtm-indiv-sync", e, true); - continue; - } - } - postUpdate(new ProgressUpdater(1, 1)); - } - - synchronizeTasks(context, remoteChanges, new RtmSyncHelper(context, timeline)); - - // set sync time in the future so we don't retrieve already - // synchronized tasks and try to merge them - Date syncTime = new Date(System.currentTimeMillis() + 1000L); - Preferences.setSyncRTMLastSync(context, syncTime); - - FlurryAgent.onEvent("rtm-sync-finished"); - } catch (IllegalStateException e) { - // occurs when application was closed - Log.w("rtmsync", "Illegal State during Sync", e); - } catch (Exception e) { - handleRtmException(context, "rtm-sync", e, true); - - } finally { - // on with the synchronization - synchronizer.continueSynchronization(context); - } - } - - // --- helper methods - - /** Add the tasks read from RTM to the given list */ - private void addTasksToList(Context context, RtmTasks tasks, LinkedList list) { - for(RtmTaskList taskList : tasks.getLists()) { - for(RtmTaskSeries taskSeries : taskList.getSeries()) { - TaskProxy remoteTask = - parseRemoteTask(taskList.getId(), taskSeries, - synchronizer.getTagController(context)); - list.add(remoteTask); - } - } - } - - /** Get a task proxy with default RTM values */ - private TaskProxy getDefaultTaskProxy() { - TaskProxy taskProxy = new TaskProxy(0, ""); - taskProxy.progressPercentage = 0; - taskProxy.tags = new LinkedList(); - taskProxy.notes = ""; - return taskProxy; - } - - /** Send changes for the given TaskProxy across the wire */ - private void pushLocalTask(String timeline, TaskProxy task, TaskProxy remoteTask, - SyncMapping mapping) throws ServiceException { - RtmId id = new RtmId(mapping.getRemoteId()); - - // fetch remote task for comparison (won't work if you renamed it) - if(remoteTask == null) { - RtmTaskSeries rtmTask = rtmService.tasks_getTask(id.taskSeriesId, task.name); - if(rtmTask != null) - remoteTask = parseRemoteTask(id.listId, rtmTask, null); - } - if(remoteTask == null) - remoteTask = getDefaultTaskProxy(); - - if(task.name != null && !task.name.equals(remoteTask.name)) - rtmService.tasks_setName(timeline, id.listId, id.taskSeriesId, - id.taskId, task.name); - if(task.importance != null && !task.importance.equals(remoteTask.importance)) - rtmService.tasks_setPriority(timeline, id.listId, id.taskSeriesId, - id.taskId, Priority.values()[task.importance.ordinal()]); - - // due date - Date dueDate = task.dueDate; - if(dueDate == null) - dueDate = task.definiteDueDate; - if(dueDate == null) - dueDate = task.preferredDueDate; - if(dueDate != remoteTask.dueDate && (dueDate == null || - !dueDate.equals(remoteTask.dueDate))) { - // note tha dueDate could be null - rtmService.tasks_setDueDate(timeline, id.listId, id.taskSeriesId, - id.taskId, dueDate, dueDate != null); - } - - // progress - if(task.progressPercentage != null && !task.progressPercentage.equals( - remoteTask.progressPercentage)) { - if(task.progressPercentage == 100) - rtmService.tasks_complete(timeline, id.listId, id.taskSeriesId, - id.taskId); - else - rtmService.tasks_uncomplete(timeline, id.listId, id.taskSeriesId, - id.taskId); - } - - // notes - if(task.notes != null && task.notes.length() > 0 && - !task.notes.equals(remoteTask.notes)) - rtmService.tasks_notes_add(timeline, id.listId, id.taskSeriesId, - id.taskId, "From Astrid", task.notes); - - // tags - if(task.tags != null && !task.tags.equals(remoteTask.tags)) { - String listName = listIdToNameMap.get(id.listId); - - // if the first tag is the list, or _list, remove it - if(task.tags.size() > 0) { - String firstTag = task.tags.getFirst(); - if(firstTag.startsWith(TagModelForView.HIDDEN_FROM_MAIN_LIST_PREFIX)) - firstTag = firstTag.substring(TagModelForView.HIDDEN_FROM_MAIN_LIST_PREFIX.length()); - if(firstTag.equals(listName)) - task.tags.remove(0); - } - - rtmService.tasks_setTags(timeline, id.listId, id.taskSeriesId, - id.taskId, task.tags.toArray(new String[task.tags.size()])); - } - - // estimated time - if(task.estimatedSeconds == 0 && remoteTask.estimatedSeconds != null || - task.estimatedSeconds > 0 && remoteTask.estimatedSeconds == null) { - String estimation; - int estimatedSeconds = task.estimatedSeconds; - if(estimatedSeconds == 0) - estimation = ""; - else if(estimatedSeconds < 3600) - estimation = estimatedSeconds/60 + " minutes"; - else if(estimatedSeconds < 24*3600) { - int hours = (estimatedSeconds/3600); - estimation = hours+ " hours "; - if(hours*3600 != estimatedSeconds) - estimation += estimatedSeconds - hours*3600 + " minutes"; - } else - estimation = estimatedSeconds/3600/24 + " days"; - rtmService.tasks_setEstimate(timeline, id.listId, id.taskSeriesId, - id.taskId, estimation); - } - } - - /** Create a task proxy for the given RtmTaskSeries */ - private TaskProxy parseRemoteTask(String listId, RtmTaskSeries - rtmTaskSeries, TagController tagController) { - TaskProxy task = new TaskProxy(getId(), - new RtmId(listId, rtmTaskSeries).toString()); - - task.name = rtmTaskSeries.getName(); - - // notes - StringBuilder sb = new StringBuilder(); - for(RtmTaskNote note: rtmTaskSeries.getNotes().getNotes()) { - sb.append(note.getTitle() + "\n"); - sb.append(note.getText() + "\n"); - } - if(sb.length() > 0) - task.notes = sb.toString().trim(); - - // repeat - if(rtmTaskSeries.hasRecurrence()) - task.syncOnComplete = true; - - // list / tags - LinkedList tagsList = rtmTaskSeries.getTags(); - String listName = listIdToNameMap.get(listId); - if(listName != null && !listName.equals(INBOX_LIST_NAME)) { - if(tagsList == null) - tagsList = new LinkedList(); - - // if user has created a hidden version of this tag, use it - String hiddenName = TagModelForView.HIDDEN_FROM_MAIN_LIST_PREFIX + listName; - if(tagController != null && tagController.fetchTagFromName(hiddenName) != null) - tagsList.addFirst(hiddenName); - else - tagsList.addFirst(listName); - } - if(tagsList != null) - task.tags = tagsList; - - RtmTask rtmTask = rtmTaskSeries.getTask(); - if(rtmTask != null) { - String estimate = rtmTask.getEstimate(); - if(estimate != null && estimate.length() > 0) { - task.estimatedSeconds = parseEstimate(estimate); - } - task.creationDate = rtmTaskSeries.getCreated(); - task.completionDate = rtmTask.getCompleted(); - task.isDeleted = rtmTask.getDeleted() != null; - if(rtmTask.getDue() != null) { - Date due = rtmTask.getDue(); - - // if no time is set, set it to midnight - if(due.getHours() == 0 && due.getMinutes() == 0 && due.getSeconds() == 0) { - due.setHours(23); - due.setMinutes(59); - } - task.dueDate = due; - } - task.progressPercentage = (rtmTask.getCompleted() == null) ? 0 : - AbstractTaskModel.COMPLETE_PERCENTAGE; - task.importance = Importance.values()[rtmTask.getPriority().ordinal()]; - } else { - // error in upstream code, try to handle gracefully - Log.e("rtmsync", "Got null task parsing remote task series", new Throwable()); - } - - return task; - } - - /** Parse an estimated time of the format ## {s,m,h,d,w,mo} and return - * the duration in seconds. Returns null on failure. */ - private Integer parseEstimate(String estimate) { - try { - float total = 0; - int position = 0; - while(position != -1) { - for(; position < estimate.length(); position++) { - char c = estimate.charAt(position); - if(c != '.' && (c < '0' || c > '9')) - break; - } - float numberPortion = Float.parseFloat(estimate.substring(0, position)); - String stringPortion = estimate.substring(position).trim(); - position = stringPortion.indexOf(" "); - if(position != -1) - estimate = stringPortion.substring(position+1).trim(); - - if(stringPortion.startsWith("mo")) - total += numberPortion * 31 * 24 * 3600; - else if(stringPortion.startsWith("w")) - total += numberPortion * 7 * 24 * 3600; - else if(stringPortion.startsWith("d")) - total += numberPortion * 24 * 3600; - else if(stringPortion.startsWith("h")) - total += numberPortion * 3600; - else if(stringPortion.startsWith("m")) - total += numberPortion * 60; - else if(stringPortion.startsWith("s")) - total += numberPortion; - } - return (int)total; - } catch (Exception e) { /* */ } - return null; - } - - // --- helper classes - - /** SynchronizeHelper for remember the milk */ - class RtmSyncHelper implements SynchronizeHelper { - private final String timeline; - private String lastCreatedTask = null; - private Context context; - - public RtmSyncHelper(Context context, String timeline) { - this.timeline = timeline; - } - public String createTask(TaskModelForSync task) throws IOException { - String listId = listNameToIdMap.get(INBOX_LIST_NAME.toLowerCase()); - RtmTaskSeries s = rtmService.tasks_add(timeline, listId, - task.getName()); - lastCreatedTask = new RtmId(listId, s).toString(); - return lastCreatedTask; - } - public void deleteTask(SyncMapping mapping) throws IOException { - RtmId id = new RtmId(mapping.getRemoteId()); - rtmService.tasks_delete(timeline, id.listId, id.taskSeriesId, - id.taskId); - } - public void pushTask(TaskProxy task, TaskProxy remoteTask, - SyncMapping mapping) throws IOException { - - // don't save the stuff that we already saved by creating the task - if(task.getRemoteId().equals(lastCreatedTask)) - task.name = null; - - pushLocalTask(timeline, task, remoteTask, mapping); - } - public TaskProxy refetchTask(TaskProxy task) throws IOException { - RtmId id = new RtmId(task.getRemoteId()); - RtmTaskSeries rtmTask = rtmService.tasks_getTask(id.taskSeriesId, - task.name); - if(rtmTask == null) - return task; // can't fetch - return parseRemoteTask(id.listId, rtmTask, synchronizer.getTagController(context)); - } - } - - /** Helper class for processing RTM id's into one field */ - private static class RtmId { - String taskId; - String taskSeriesId; - String listId; - - public RtmId(String listId, RtmTaskSeries taskSeries) { - if(taskSeries.getTask() == null) { - Log.w("rtm", "Error - found task with no task id"); - this.taskId = ""; - } else - this.taskId = taskSeries.getTask().getId(); - this.taskSeriesId = taskSeries.getId(); - this.listId = listId; - } - - public RtmId(String id) { - StringTokenizer strtok = new StringTokenizer(id, "|"); - taskId = strtok.nextToken(); - taskSeriesId = strtok.nextToken(); - listId = strtok.nextToken(); - } - - @Override - public String toString() { - return taskId + "|" + taskSeriesId + "|" + listId; - } - } -} diff --git a/astrid/src-legacy/com/timsu/astrid/sync/SynchronizationProvider.java b/astrid/src-legacy/com/timsu/astrid/sync/SynchronizationProvider.java deleted file mode 100644 index 21b77f869..000000000 --- a/astrid/src-legacy/com/timsu/astrid/sync/SynchronizationProvider.java +++ /dev/null @@ -1,684 +0,0 @@ -/* - * ASTRID: Android's Simple Task Recording Dashboard - * - * Copyright (c) 2009 Tim Su - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.timsu.astrid.sync; - -import java.io.IOException; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; - -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.res.Resources; -import android.os.Handler; -import android.util.Log; - -import com.flurry.android.FlurryAgent; -import com.timsu.astrid.R; -import com.timsu.astrid.data.alerts.AlertController; -import com.timsu.astrid.data.sync.SyncDataController; -import com.timsu.astrid.data.sync.SyncMapping; -import com.timsu.astrid.data.tag.TagController; -import com.timsu.astrid.data.tag.TagIdentifier; -import com.timsu.astrid.data.tag.TagModelForView; -import com.timsu.astrid.data.task.AbstractTaskModel; -import com.timsu.astrid.data.task.TaskController; -import com.timsu.astrid.data.task.TaskIdentifier; -import com.timsu.astrid.data.task.TaskModelForSync; -import com.timsu.astrid.utilities.AstridUtilities; -import com.timsu.astrid.utilities.DialogUtilities; -import com.timsu.astrid.utilities.Preferences; - -/** A service that synchronizes with Astrid - * - * @author timsu - * - */ -public abstract class SynchronizationProvider { - - private final int id; - static ProgressDialog progressDialog; - private Handler syncHandler; - protected Synchronizer synchronizer; - - public SynchronizationProvider(int id) { - this.id = id; - } - - /** Does some setup and then invokes implemented synchronize method. Call me - * on the UI thread! - * - * @param activity - * @param caller - */ - void synchronizeService(final Context context, Synchronizer caller) { - this.synchronizer = caller; - - if(!isBackgroundService()) { - try { - this.syncHandler = new Handler(); - syncHandler.post(new Runnable() { - @Override - public void run() { - SynchronizationProvider.progressDialog = new ProgressDialog(context); - progressDialog.setIcon(android.R.drawable.ic_dialog_info); - progressDialog.setTitle("Synchronization"); - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - progressDialog.setMax(100); - progressDialog.setMessage("Checking Authorization..."); - progressDialog.setProgress(0); - progressDialog.setCancelable(false); - } - }); - } catch (IllegalStateException e) { - Log.w("sync", "Wasn't in UI thread when creating handler."); - syncHandler = null; - } - } - - synchronize(context); - } - - /** Synchronize with the service */ - protected abstract void synchronize(Context activity); - - /** Called when user requests a data clear */ - abstract void clearPersonalData(Context activity); - - /** Get this service's id */ - public int getId() { - return id; - } - - /** Gets this service's name */ - abstract String getName(); - - // --- utilities - - /** Check whether this synchronization request is running in the background - * @return true if it's running as a background service - */ - protected boolean isBackgroundService() { - return synchronizer.isService(); - } - - /** Check whether the synchronization request wants to only transmit - * one specific task. Returns null if this is not the case */ - protected TaskIdentifier getSingleTaskForSync() { - return synchronizer.getSingleTaskForSync(); - } - - /** Utility method for showing synchronization errors. If message is null, - * the contents of the throwable is displayed. It is assumed that the - * error was logged separately. - */ - void showError(final Context context, Throwable e, String message) { - if(isBackgroundService()) - return; - - Resources r = context.getResources(); - final String messageToDisplay; - if(message == null) { - messageToDisplay = r.getString(R.string.sync_error) + " " + - e.toString() + " - " + e.getStackTrace()[1]; - } else { - messageToDisplay = message; - } - syncHandler.post(new Runnable() { - public void run() { - try { - if(progressDialog != null) - progressDialog.dismiss(); - } catch (Exception e) { - // suppress it - } - DialogUtilities.okDialog(context, messageToDisplay, null); - } - }); - } - - /** Utility method to update the UI if we're an active sync, or output - * to console if we're a background sync. - */ - protected void postUpdate(Runnable updater) { - if(isBackgroundService() || syncHandler == null) { - // only run jobs if they can actually be processed - if(updater instanceof ProgressLabelUpdater) - updater.run(); - } else { - syncHandler.post(updater); - } - } - - // --- synchronization logic - - /** interface to assist with synchronization */ - protected interface SynchronizeHelper { - /** Push the given task to the remote server. - * - * @param task task proxy to push - * @param remoteTask remote task that we merged with, or null - * @param mapping local/remote mapping. - */ - void pushTask(TaskProxy task, TaskProxy remoteTask, - SyncMapping mapping) throws IOException; - - /** Create a task on the remote server. This is followed by a call of - * pushTask on the id in question. - * - * @return task to create - * @return remote id - */ - String createTask(TaskModelForSync task) throws IOException; - - /** Fetch remote task. Used to re-read merged tasks - * - * @param task TaskProxy of the original task - * @return new TaskProxy - */ - TaskProxy refetchTask(TaskProxy task) throws IOException; - - /** Delete the task from the remote server - * - * @param mapping mapping to delete - */ - void deleteTask(SyncMapping mapping) throws IOException; - } - - /** Helper to synchronize remote tasks with our local database. - * - * This initiates the following process: - * 1. local changes are read - * 2. remote changes are read - * 3. local tasks are merged with remote changes and pushed across - * 4. remote changes are then read in - * - * @param remoteTasks remote tasks that have been updated - * @return local tasks that need to be pushed across - */ - protected synchronized void synchronizeTasks(final Context context, LinkedList - remoteTasks, SynchronizeHelper helper) throws IOException { - final SyncStats stats = new SyncStats(); - final StringBuilder log = new StringBuilder(); - - SyncDataController syncController = synchronizer.getSyncController(context); - TaskController taskController = synchronizer.getTaskController(context); - TagController tagController = synchronizer.getTagController(context); - AlertController alertController = synchronizer.getAlertController(context); - SyncData data = new SyncData(context, remoteTasks); - - // 1. CREATE: grab tasks without a sync mapping and create them remotely - log.append(">> on remote server:\n"); - for(TaskIdentifier taskId : data.newlyCreatedTasks) { - TaskModelForSync task = taskController.fetchTaskForSync(taskId); - postUpdate(new ProgressLabelUpdater(context, R.string.sync_progress_localtx, - task.getName().replaceAll("%", "%%"))); - postUpdate(new ProgressUpdater(stats.remoteCreatedTasks, - data.newlyCreatedTasks.size())); - - /* If there exists an incoming remote task with the same name and - * no mapping, we don't want to create this on the remote server. - * Instead, we create a mapping and do an update. */ - if(data.newRemoteTasks.containsKey(task.getName())) { - TaskProxy remoteTask = data.newRemoteTasks.get(task.getName()); - SyncMapping mapping = new SyncMapping(taskId, getId(), - remoteTask.getRemoteId()); - syncController.saveSyncMapping(mapping); - data.localChanges.add(mapping); - data.remoteChangeMap.put(taskId, remoteTask); - data.localIdToSyncMapping.put(taskId, mapping); - continue; - } - - String remoteId = helper.createTask(task); - SyncMapping mapping = new SyncMapping(taskId, getId(), remoteId); - syncController.saveSyncMapping(mapping); - data.localIdToSyncMapping.put(taskId, mapping); - - TaskProxy localTask = new TaskProxy(getId(), remoteId); - localTask.readFromTaskModel(task); - localTask.readTagsFromController(taskId, tagController, data.tags); - helper.pushTask(localTask, null, mapping); - - // update stats - log.append("added '" + task.getName() + "'\n"); - stats.remoteCreatedTasks++; - } - - // 2. DELETE: find deleted tasks and remove them from the list - postUpdate(new ProgressLabelUpdater(context, R.string.sync_progress_localdel)); - for(TaskIdentifier taskId : data.deletedTasks) { - SyncMapping mapping = data.localIdToSyncMapping.get(taskId); - syncController.deleteSyncMapping(mapping); - helper.deleteTask(mapping); - - // remove it from data structures - data.localChanges.remove(mapping); - data.localIdToSyncMapping.remove(taskId); - data.remoteIdToSyncMapping.remove(mapping.getRemoteId()); - data.remoteChangeMap.remove(taskId); - - // update stats - log.append("deleted id #" + taskId.getId() + "\n"); - stats.remoteDeletedTasks++; - postUpdate(new ProgressUpdater(stats.remoteDeletedTasks, - data.deletedTasks.size())); - } - - // 3. UPDATE: for each updated local task - for(SyncMapping mapping : data.localChanges) { - TaskProxy localTask = null; - TaskModelForSync task = null; - try { - localTask = new TaskProxy(getId(), mapping.getRemoteId()); - task = taskController.fetchTaskForSync( - mapping.getTask()); - if(task == null) { - // sucks... task was deleted i guess. - continue; - } - localTask.readFromTaskModel(task); - localTask.readTagsFromController(task.getTaskIdentifier(), - tagController, data.tags); - postUpdate(new ProgressLabelUpdater(context, R.string.sync_progress_localtx, - task.getName().replaceAll("%", "%%"))); - } catch (Exception e) { - AstridUtilities.reportFlurryError("sync-read-local-task", e); - Log.e("astrid", "Exception receiving task", e); - if(task != null) - log.append("error reading '" + task.getName() + "'\n"); - else - log.append("error reading local task\n"); - - continue; - } finally { - postUpdate(new ProgressUpdater(stats.remoteUpdatedTasks, - data.localChanges.size())); - } - - // if there is a conflict, merge - TaskProxy remoteConflict = null; - if(data.remoteChangeMap.containsKey(mapping.getTask())) { - remoteConflict = data.remoteChangeMap.get(mapping.getTask()); - // merging disabled - seems not to do the right thing - // localTask.mergeWithOther(remoteConflict); - stats.mergedTasks++; - } else { - stats.remoteUpdatedTasks++; - } - - try { - helper.pushTask(localTask, remoteConflict, mapping); - if(remoteConflict != null) - log.append("merged '" + task.getName() + "'\n"); - else - log.append("updated '" + task.getName() + "'\n"); - } catch (Exception e) { - AstridUtilities.reportFlurryError("sync-push-task", e); - - Log.e("astrid", "Exception pushing task", e); - log.append("error sending '" + task.getName() + "'\n"); - continue; - } - - // re-fetch remote task - if(remoteConflict != null || getSingleTaskForSync() != null) { - TaskProxy newTask = helper.refetchTask(remoteConflict); - remoteTasks.remove(remoteConflict); - remoteTasks.add(newTask); - } - } - - // 4. REMOTE SYNC load remote information - log.append("\n>> on astrid:\n"); - postUpdate(new ProgressUpdater(0, 1)); - - // Rearrange remoteTasks so completed tasks get synchronized first. - // This prevents bugs where a repeated task has two copies come down - // the wire, the new version and the completed old version. The new - // version would get merged, then completed, if done in the wrong order. - - Collections.sort(remoteTasks, new Comparator() { - @Override - public int compare(TaskProxy object1, TaskProxy object2) { - if(object1.isDeleted && object2.isDeleted) - return 0; - else if(object1.isDeleted) - return -1; - else if(object2.isDeleted()) - return 1; - - if(object1.completionDate != null && object2.completionDate != null) - return object1.completionDate.compareTo(object2.completionDate); - else if(object1.completionDate != null) - return -1; - else if(object2.completionDate != null) - return 1; - - return 0; - } - }); - - for(TaskProxy remoteTask : remoteTasks) { - if(remoteTask.name != null) - postUpdate(new ProgressLabelUpdater(context, R.string.sync_progress_remotetx, - remoteTask.name)); - SyncMapping mapping = null; - TaskModelForSync task = null; - - // if it's new, create a new task model - if(!data.remoteIdToSyncMapping.containsKey(remoteTask.getRemoteId())) { - // if it's new & deleted, forget about it - if(remoteTask.isDeleted() || remoteTask.progressPercentage == - AbstractTaskModel.COMPLETE_PERCENTAGE) { - continue; - } - - task = taskController.searchForTaskForSync(remoteTask.name); - - if(task == null) { - task = new TaskModelForSync(); - setupTaskDefaults(context, task); - log.append("added " + remoteTask.name + "\n"); - } else { - log.append("merged " + remoteTask.name + "\n"); - - // delete old mapping - mapping = data.localIdToSyncMapping.get(task.getTaskIdentifier()); - if(mapping != null) { - syncController.deleteSyncMapping(mapping); - data.localIdToSyncMapping.remove(task.getTaskIdentifier()); - mapping = null; - } - } - } else { - mapping = data.remoteIdToSyncMapping.get(remoteTask.getRemoteId()); - if(remoteTask.isDeleted()) { - taskController.deleteTask(mapping.getTask()); - syncController.deleteSyncMapping(mapping); - log.append("deleted " + remoteTask.name + "\n"); - stats.localDeletedTasks++; - continue; - } - - log.append("updated '" + remoteTask.name + "'\n"); - task = taskController.fetchTaskForSync( - mapping.getTask()); - } - - // save the data - remoteTask.writeToTaskModel(task); - taskController.saveTask(task, true); - - // save tags - LinkedList taskTags = tagController.getTaskTags(task.getTaskIdentifier()); - if(remoteTask.tags != null) { - HashSet tagsToAdd = new HashSet(); - for(String tag : remoteTask.tags) { - String tagLower = tag.toLowerCase(); - if(!data.tagsByLCName.containsKey(tagLower)) { - TagIdentifier tagId = tagController.createTag(tag); - data.tagsByLCName.put(tagLower, tagId); - tagsToAdd.add(tagId); - } else - tagsToAdd.add(data.tagsByLCName.get(tagLower)); - } - - HashSet tagsToDelete = new HashSet(taskTags); - tagsToDelete.removeAll(tagsToAdd); - tagsToAdd.removeAll(taskTags); - - for(TagIdentifier tagId : tagsToDelete) - tagController.removeTag(task.getTaskIdentifier(), tagId); - for(TagIdentifier tagId : tagsToAdd) - tagController.addTag(task.getTaskIdentifier(), tagId); - } else { - // remove existing tags - for(TagIdentifier tagId : taskTags) { - tagController.removeTag(task.getTaskIdentifier(), tagId); - } - } - stats.localUpdatedTasks++; - - // try looking for this task if it doesn't already have a mapping - if(mapping == null) { - mapping = data.localIdToSyncMapping.get(task.getTaskIdentifier()); - if(mapping == null) { - try { - mapping = new SyncMapping(task.getTaskIdentifier(), remoteTask); - syncController.saveSyncMapping(mapping); - data.localIdToSyncMapping.put(task.getTaskIdentifier(), - mapping); - } catch (Exception e) { - // unique violation: ignore - it'll get merged later - Log.e("astrid-sync", "Exception creating mapping", e); - } - } - stats.localCreatedTasks++; - } - -// ReminderService.updateAlarm(context, taskController, alertController, -// task); - postUpdate(new ProgressUpdater(stats.localUpdatedTasks, - remoteTasks.size())); - } - stats.localUpdatedTasks -= stats.localCreatedTasks; - - syncController.clearUpdatedTaskList(getId()); - postUpdate(new Runnable() { - public void run() { - stats.showDialog(context, log.toString()); - } - }); - } - - /** Set up defaults from preferences for this task */ - private void setupTaskDefaults(Context context, TaskModelForSync task) { - Integer reminder = Preferences.getDefaultReminder(context); - if(reminder != null) - task.setNotificationIntervalSeconds(24*3600*reminder); - } - - // --- helper classes - - /** data structure builder */ - class SyncData { - HashSet mappings; - HashSet activeTasks; - HashSet allTasks; - - HashMap remoteIdToSyncMapping; - HashMap localIdToSyncMapping; - - HashSet localChanges; - HashSet mappedTasks; - HashMap remoteChangeMap; - HashMap newRemoteTasks; - - HashMap tags; - HashMap tagsByLCName; - - HashSet newlyCreatedTasks; - HashSet deletedTasks; - - public SyncData(Context context, LinkedList remoteTasks) { - // 1. get data out of the database - mappings = synchronizer.getSyncController(context).getSyncMappings(getId()); - activeTasks = synchronizer.getTaskController(context).getActiveTaskIdentifiers(); - allTasks = synchronizer.getTaskController(context).getAllTaskIdentifiers(); - tags = synchronizer.getTagController(context).getAllTagsAsMap(); - - // 2. build helper data structures - remoteIdToSyncMapping = new HashMap(); - localIdToSyncMapping = new HashMap(); - mappedTasks = new HashSet(); - for(SyncMapping mapping : mappings) { - remoteIdToSyncMapping.put(mapping.getRemoteId(), mapping); - localIdToSyncMapping.put(mapping.getTask(), mapping); - mappedTasks.add(mapping.getTask()); - } - tagsByLCName = new HashMap(); - for(TagModelForView tag : tags.values()) - tagsByLCName.put(tag.getName().toLowerCase(), tag.getTagIdentifier()); - - // 3. build map of remote tasks - remoteChangeMap = new HashMap(); - newRemoteTasks = new HashMap(); - for(TaskProxy remoteTask : remoteTasks) { - if(remoteIdToSyncMapping.containsKey(remoteTask.getRemoteId())) { - SyncMapping mapping = remoteIdToSyncMapping.get(remoteTask.getRemoteId()); - remoteChangeMap.put(mapping.getTask(), remoteTask); - } else if(remoteTask.name != null){ - newRemoteTasks.put(remoteTask.name, remoteTask); - } - } - - // 4. build data structures of things to do - if(getSingleTaskForSync() != null) { - newlyCreatedTasks = new HashSet(); - deletedTasks = new HashSet(); - localChanges = new HashSet(); - } else { - newlyCreatedTasks = new HashSet(activeTasks); - newlyCreatedTasks.removeAll(mappedTasks); - deletedTasks = new HashSet(mappedTasks); - deletedTasks.removeAll(allTasks); - localChanges = new HashSet(); - for(SyncMapping mapping : localIdToSyncMapping.values()) { - if(mapping.isUpdated()) - localChanges.add(mapping); - } - } - } - } - - - /** statistics tracking and displaying */ - protected class SyncStats { - int localCreatedTasks = 0; - int localUpdatedTasks = 0; - int localDeletedTasks = 0; - - int mergedTasks = 0; - - int remoteCreatedTasks = 0; - int remoteUpdatedTasks = 0; - int remoteDeletedTasks = 0; - - /** Display a dialog with statistics */ - public void showDialog(final Context context, String log) { - progressDialog.hide(); - - HashMap args = new HashMap(); - args.put("localCreatedTasks", Integer.toString(localCreatedTasks)); - args.put("localUpdatedTasks", Integer.toString(localUpdatedTasks)); - args.put("localDeletedTasks", Integer.toString(localDeletedTasks)); - args.put("mergedTasks", Integer.toString(mergedTasks)); - args.put("remoteCreatedTasks", Integer.toString(remoteCreatedTasks)); - args.put("remoteUpdatedTasks", Integer.toString(remoteUpdatedTasks)); - args.put("remoteDeletedTasks", Integer.toString(remoteDeletedTasks)); - FlurryAgent.onEvent("sync-finished", args); - - if(Preferences.shouldSuppressSyncDialogs(context) || - getSingleTaskForSync() != null) { - return; - } - - Resources r = context.getResources(); - Dialog.OnClickListener finishListener = null; - - // nothing updated - if(localCreatedTasks + localUpdatedTasks + localDeletedTasks + - mergedTasks + remoteCreatedTasks + remoteDeletedTasks + - remoteUpdatedTasks == 0) { - if(!isBackgroundService()) - DialogUtilities.okDialog(context, context.getResources(). - getString(R.string.sync_uptodate), finishListener); - return; - } - - StringBuilder sb = new StringBuilder(); - sb.append(r.getString(R.string.sync_result_title, getName())); - sb.append("\n\n"); - sb.append(log).append("\n"); - if(localCreatedTasks + localUpdatedTasks + localDeletedTasks > 0) - sb.append(r.getString(R.string.sync_result_local)).append("\n"); - if(localCreatedTasks > 0) - sb.append(r.getString(R.string.sync_result_created, localCreatedTasks)).append("\n"); - if(localUpdatedTasks > 0) - sb.append(r.getString(R.string.sync_result_updated, localUpdatedTasks)).append("\n"); - if(localDeletedTasks > 0) - sb.append(r.getString(R.string.sync_result_deleted, localDeletedTasks)).append("\n"); - - if(mergedTasks > 0) - sb.append("\n").append(r.getString(R.string.sync_result_merged, mergedTasks)).append("\n"); - sb.append("\n"); - - if(remoteCreatedTasks + remoteDeletedTasks + remoteUpdatedTasks > 0) - sb.append(r.getString(R.string.sync_result_remote)).append("\n"); - if(remoteCreatedTasks > 0) - sb.append(r.getString(R.string.sync_result_created, remoteCreatedTasks)).append("\n"); - if(remoteUpdatedTasks > 0) - sb.append(r.getString(R.string.sync_result_updated, remoteUpdatedTasks)).append("\n"); - if(remoteDeletedTasks > 0) - sb.append(r.getString(R.string.sync_result_deleted, remoteDeletedTasks)).append("\n"); - - sb.append("\n"); - - DialogUtilities.okDialog(context, sb.toString(), finishListener); - } - } - - protected class ProgressUpdater implements Runnable { - int step, outOf; - public ProgressUpdater(int step, int outOf) { - this.step = step; - this.outOf = outOf; - } - public void run() { - if(!isBackgroundService()) - progressDialog.setProgress(100*step/outOf); - } - } - - protected class ProgressLabelUpdater implements Runnable { - String label; - public ProgressLabelUpdater(Context context, int id, Object... args) { - try { - this.label = context.getResources().getString(id, args); - } catch (Exception e) { - Log.e("sync-progress", "Error formatting progress label", e); - this.label = context.getResources().getString(id); - } - } - public void run() { - if(isBackgroundService()) { - Log.i("astrid-sync", label); - } else { - if(!progressDialog.isShowing()) - progressDialog.show(); - progressDialog.setMessage(label); - } - } - } -} diff --git a/astrid/src-legacy/com/timsu/astrid/sync/SynchronizationService.java b/astrid/src-legacy/com/timsu/astrid/sync/SynchronizationService.java deleted file mode 100644 index ef8dd857b..000000000 --- a/astrid/src-legacy/com/timsu/astrid/sync/SynchronizationService.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.timsu.astrid.sync; - -import java.util.Date; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.util.Log; - -import com.timsu.astrid.utilities.Constants; -import com.timsu.astrid.utilities.Preferences; - -/** - * SynchronizationService is the service that performs Astrid's background - * synchronization with online task managers. Starting this service - * schedules a repeating alarm which handles the synchronization - * - * @author Tim Su - * - */ -public class SynchronizationService extends Service { - - /** miniumum time before an auto-sync */ - private static final long AUTO_SYNC_MIN_OFFSET = 5*60*1000L; - - /** alarm identifier */ - private static final String SYNC_ACTION = "sync"; - - // --- BroadcastReceiver abstract methods - - /** Receive the alarm - start the synchronize service! */ - @Override - public void onStart(Intent intent, int startId) { - Log.i("astrid", "wassup"); - if(intent.getAction().equals(SYNC_ACTION)) - startSynchronization(this); - } - - /** Start the actual synchronization */ - private void startSynchronization(Context context) { - if(context == null || context.getResources() == null) - return; - - // figure out synchronization frequency - Integer syncFrequencySeconds = Preferences.getSyncAutoSyncFrequency(context); - if(syncFrequencySeconds == null) - return; - long interval = 1000L * syncFrequencySeconds; - long offset = computeNextSyncOffset(context, interval); - - // if premature request for sync (i.e. user invoked manual sync, - // reschedule our service - if(offset != 0) { - Log.i("astrid", "Automatic Synchronize Postponed."); - return; - } - - Log.i("astrid", "Automatic Synchronize Initiated."); - Preferences.setSyncLastSyncAttempt(context, new Date()); - - Synchronizer sync = new Synchronizer(true); - sync.synchronize(context, null); - } - - // --- alarm management - - /** - * Schedules repeating alarm for auto-synchronization - */ - public static void scheduleService(Context context) { - Integer syncFrequencySeconds = Preferences.getSyncAutoSyncFrequency(context); - - if(syncFrequencySeconds == null) { - Log.w("sync-service", "disabled synchronization service"); - unscheduleService(context); - return; - } - - // figure out synchronization frequency - long interval = 1000L * syncFrequencySeconds; - long offset = computeNextSyncOffset(context, interval); - - // give a little padding - offset = Math.max(offset, AUTO_SYNC_MIN_OFFSET); - - AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); - PendingIntent pendingIntent = PendingIntent.getService(context, 0, - createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT); - - if (Constants.DEBUG) - Log.e("Astrid", "Autosync set for " + offset / 1000 - + " seconds repeating every " + syncFrequencySeconds); - - // cancel all existing - am.cancel(pendingIntent); - - // schedule new - am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + offset, - interval, pendingIntent); - } - - - /** - * Removes repeating alarm for auto-synchronization - */ - public static void unscheduleService(Context context) { - AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); - PendingIntent pendingIntent = PendingIntent.getService(context, 0, - createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT); - am.cancel(pendingIntent); - } - - /** Create the alarm intent */ - private static Intent createAlarmIntent(Context context) { - Intent intent = new Intent(context, SynchronizationService.class); - intent.setAction(SYNC_ACTION); - return intent; - } - - // --- utility methods - - - private static long computeNextSyncOffset(Context context, long interval) { - // figure out last synchronize time - Date lastSyncDate = Preferences.getSyncLastSync(context); - Date lastAutoSyncDate = Preferences.getSyncLastSyncAttempt(context); - - // if user never synchronized, give them a full offset period before bg sync - long latestSyncMillis = System.currentTimeMillis(); - if(lastSyncDate != null) - latestSyncMillis = lastSyncDate.getTime(); - if(lastAutoSyncDate != null && lastAutoSyncDate.getTime() > latestSyncMillis) - latestSyncMillis = lastAutoSyncDate.getTime(); - long offset = 0; - if(latestSyncMillis != 0) - offset = Math.max(0, latestSyncMillis + interval - System.currentTimeMillis()); - - return offset; - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - -} diff --git a/astrid/src-legacy/com/timsu/astrid/sync/Synchronizer.java b/astrid/src-legacy/com/timsu/astrid/sync/Synchronizer.java deleted file mode 100644 index 38bf96f9c..000000000 --- a/astrid/src-legacy/com/timsu/astrid/sync/Synchronizer.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * ASTRID: Android's Simple Task Recording Dashboard - * - * Copyright (c) 2009 Tim Su - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.timsu.astrid.sync; - -import java.lang.reflect.InvocationTargetException; -import java.util.Date; - -import android.app.Activity; -import android.content.Context; -import android.util.Log; - -import com.timsu.astrid.data.AbstractController; -import com.timsu.astrid.data.alerts.AlertController; -import com.timsu.astrid.data.sync.SyncDataController; -import com.timsu.astrid.data.tag.TagController; -import com.timsu.astrid.data.task.TaskController; -import com.timsu.astrid.data.task.TaskIdentifier; -import com.timsu.astrid.utilities.AstridUtilities; -import com.timsu.astrid.utilities.Preferences; - -/** - * Synchronizer is a class that manages a synchronization lifecycle. You would - * use it as follows. - *

- *

Synchronizer synchronizer = new Synchronizer(...);
- * synchronizer.synchronize();
- * - * @author Tim Su - * - */ -public class Synchronizer { - - /** identifier for the RTM sync provider */ - private static final int SYNC_ID_RTM = 1; - - // --- public interface - - /** Synchronize all tasks */ - public Synchronizer(boolean isService) { - this.isService = isService; - singleTaskForSync = null; - } - - /** Synchronize a specific task only */ - public Synchronizer(TaskIdentifier task) { - isService = false; - singleTaskForSync = task; - } - - public interface SynchronizerListener { - void onSynchronizerFinished(int numServicesSynced); - } - - /** Synchronize all activated sync services. */ - public synchronized void synchronize(Context context, - SynchronizerListener listener) { - currentStep = ServiceWrapper._FIRST_SERVICE.ordinal(); - servicesSynced = 0; - callback = listener; - - continueSynchronization(context); - } - - - /** Clears tokens of activated services */ - public static void clearUserData(Activity activity) { - Synchronizer synchronizer = new Synchronizer(false); - for(ServiceWrapper serviceWrapper : ServiceWrapper.values()) { - if(serviceWrapper.isActivated(activity)) { - serviceWrapper.service.synchronizer = synchronizer; - serviceWrapper.service.clearPersonalData(activity); - } - } - synchronizer.closeControllers(); - } - - // --- internal synchronization logic - - /** Synchronization Services enumeration - * note that id must be kept constant! - * @author timsu - * - */ - private enum ServiceWrapper { - _FIRST_SERVICE(null) { // must be first entry - @Override - boolean isActivated(Context arg0) { - return false; - } - }, - - RTM(new RTMSyncProvider(SYNC_ID_RTM)) { - @Override - boolean isActivated(Context context) { - return Preferences.shouldSyncRTM(context); - } - }, - - _LAST_SERVICE(null) { // must be last entry - @Override - boolean isActivated(Context arg0) { - return false; - } - }; - - private SynchronizationProvider service; - - private ServiceWrapper(SynchronizationProvider service) { - this.service = service; - } - - abstract boolean isActivated(Context context); - } - - // Internal state for the synchronization process - - /** Current step in the sync process */ - private int currentStep = 0; - - /** # of services synchronized */ - private int servicesSynced = 0; - - /** On finished callback */ - private SynchronizerListener callback = null; - - /** Whether this sync is initiated by a background service */ - private final boolean isService; - - /** The single task to synchronize, if applicable */ - private final TaskIdentifier singleTaskForSync; - - boolean isService() { - return isService; - } - - TaskIdentifier getSingleTaskForSync() { - return singleTaskForSync; - } - - /** Called to do the next step of synchronization. */ - void continueSynchronization(Context context) { - try { - if(currentStep >= ServiceWrapper.values().length) - currentStep = ServiceWrapper.values().length - 1; - - ServiceWrapper serviceWrapper = - ServiceWrapper.values()[currentStep]; - currentStep++; - switch(serviceWrapper) { - case _FIRST_SERVICE: - continueSynchronization(context); - break; - case RTM: - if(serviceWrapper.isActivated(context)) { - servicesSynced++; - serviceWrapper.service.synchronizeService(context, this); - } else { - continueSynchronization(context); - } - break; - case _LAST_SERVICE: - finishSynchronization(context); - } - } catch (Exception e) { - Log.e("sync", "Error continuing synchronization", e); - AstridUtilities.reportFlurryError("sync-continue", e); - finishSynchronization(context); - } - } - - /** Called at the end of sync. */ - private void finishSynchronization(final Context context) { - closeControllers(); - if(callback != null) - callback.onSynchronizerFinished(servicesSynced); - - if(getSingleTaskForSync() == null) - Preferences.setSyncLastSync(context, new Date()); - if(!isService) { -// TaskListSubActivity.shouldRefreshTaskList = true; - } - - Log.i("sync", "Synchronization Service Finished"); - } - - // --- controller stuff - - private final ControllerWrapper syncController = - new ControllerWrapper(SyncDataController.class); - private final ControllerWrapper taskController = - new ControllerWrapper(TaskController.class); - private final ControllerWrapper tagController = - new ControllerWrapper(TagController.class); - private final ControllerWrapper alertController = - new ControllerWrapper(AlertController.class); - - private static class ControllerWrapper { - TYPE controller; - Class typeClass; - boolean override; - - public ControllerWrapper(Class cls) { - override = false; - controller = null; - typeClass = cls; - } - - @SuppressWarnings("unchecked") - public TYPE get(Context context) { - if(controller == null) { - try { - controller = (TYPE) typeClass.getConstructors()[0].newInstance(context); - } catch (IllegalArgumentException e) { - Log.e(getClass().getSimpleName(), e.toString()); - } catch (SecurityException e) { - Log.e(getClass().getSimpleName(), e.toString()); - } catch (InstantiationException e) { - Log.e(getClass().getSimpleName(), e.toString()); - } catch (IllegalAccessException e) { - Log.e(getClass().getSimpleName(), e.toString()); - } catch (InvocationTargetException e) { - Log.e(getClass().getSimpleName(), e.toString()); - } - controller.open(); - } - return controller; - } - - public void set(TYPE newController) { - if(controller != null && !override) - close(); - - override = newController != null; - controller = newController; - } - - public void close() { - if(controller != null && !override) { - controller.close(); - controller = null; - } - } - } - - SyncDataController getSyncController(Context context) { - return syncController.get(context); - } - - TaskController getTaskController(Context context) { - return taskController.get(context); - } - - TagController getTagController(Context context) { - return tagController.get(context); - } - - AlertController getAlertController(Context context) { - return alertController.get(context); - } - - public void setTaskController(TaskController taskController) { - this.taskController.set(taskController); - } - - public void setTagController(TagController tagController) { - this.tagController.set(tagController); - } - - private void closeControllers() { - syncController.close(); - taskController.close(); - tagController.close(); - alertController.close(); - } -} diff --git a/astrid/src-legacy/com/timsu/astrid/sync/TaskProxy.java b/astrid/src-legacy/com/timsu/astrid/sync/TaskProxy.java deleted file mode 100644 index e6cf699cb..000000000 --- a/astrid/src-legacy/com/timsu/astrid/sync/TaskProxy.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * ASTRID: Android's Simple Task Recording Dashboard - * - * Copyright (c) 2009 Tim Su - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.timsu.astrid.sync; - -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; - -import com.timsu.astrid.data.enums.Importance; -import com.timsu.astrid.data.enums.RepeatInterval; -import com.timsu.astrid.data.tag.TagController; -import com.timsu.astrid.data.tag.TagIdentifier; -import com.timsu.astrid.data.tag.TagModelForView; -import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo; -import com.timsu.astrid.data.task.TaskIdentifier; -import com.timsu.astrid.data.task.TaskModelForSync; - -/** Representation of a task on a remote server. Your synchronization - * service should instantiate these, filling out every field (use null - * where the field does not exist). - * - * @author timsu - * - */ -public class TaskProxy { - - public static final Date NO_DATE_SET = new Date(0); - public static final RepeatInfo NO_REPEAT_SET = new RepeatInfo(RepeatInterval.DAYS, 0); - - TaskProxy(int syncServiceId, String syncTaskId) { - this.syncServiceId = syncServiceId; - this.syncTaskId = syncTaskId; - } - - // --- fill these out - - String name = null; - String notes = null; - - Importance importance = null; - Integer progressPercentage = null; - - Date creationDate = null; - Date completionDate = null; - - Date dueDate = null; - Date definiteDueDate = null; - Date preferredDueDate = null; - Date hiddenUntil = null; - - LinkedList tags = null; - - Integer estimatedSeconds = null; - Integer elapsedSeconds = null; - RepeatInfo repeatInfo = null; - - Boolean syncOnComplete = null; - - /** was the task deleted on the remote server */ - boolean isDeleted = false; - - // --- internal state - - /** id of the synchronization service */ - private int syncServiceId; - - /** id of this particular remote task */ - private String syncTaskId; - - - public int getSyncServiceId() { - return syncServiceId; - } - - public String getRemoteId() { - return syncTaskId; - } - - public boolean isDeleted() { - return isDeleted; - } - - // --- helper methods - - /** Merge with another TaskProxy. Fields in this taskProxy will be overwritten! */ - public void mergeWithOther(TaskProxy other) { - if(other == null) - return; - - if(other.name != null) - name = other.name; - if(other.notes != null) - notes = other.notes; - if(other.importance != null) - importance = other.importance; - if(other.progressPercentage != null) - progressPercentage = other.progressPercentage; - if(other.creationDate != null) - creationDate = other.creationDate; - if(other.completionDate != null) - completionDate = other.completionDate; - if(other.dueDate != null) - dueDate = other.dueDate; - if(other.definiteDueDate != null) - definiteDueDate = other.definiteDueDate; - if(other.preferredDueDate != null) - preferredDueDate = other.preferredDueDate; - if(other.hiddenUntil != null) - hiddenUntil = other.hiddenUntil; - if(other.tags != null) - tags = other.tags; - if(other.estimatedSeconds != null) - estimatedSeconds = other.estimatedSeconds; - if(other.elapsedSeconds != null) - elapsedSeconds = other.elapsedSeconds; - if(other.repeatInfo != null) - repeatInfo = other.repeatInfo; - if(other.syncOnComplete != null) - syncOnComplete = other.syncOnComplete; - } - - /** Read from the given task model */ - public void readFromTaskModel(TaskModelForSync task) { - name = task.getName(); - notes = task.getNotes(); - importance = task.getImportance(); - progressPercentage = task.getProgressPercentage(); - creationDate = task.getCreationDate(); - completionDate = task.getCompletionDate(); - definiteDueDate = task.getDefiniteDueDate(); - preferredDueDate = task.getPreferredDueDate(); - dueDate = definiteDueDate != null ? definiteDueDate : preferredDueDate; - hiddenUntil = task.getHiddenUntil(); - estimatedSeconds = task.getEstimatedSeconds(); - elapsedSeconds = task.getElapsedSeconds(); - syncOnComplete = (task.getFlags() & TaskModelForSync.FLAG_SYNC_ON_COMPLETE) > 0; - repeatInfo = task.getRepeat(); - } - - /** Read tags from the given tag controller */ - public void readTagsFromController(TaskIdentifier taskId, - TagController tagController, HashMap - tagList) { - LinkedList tagIds = tagController.getTaskTags(taskId); - tags = new LinkedList(); - for(TagIdentifier tagId : tagIds) { - tags.add(tagList.get(tagId).getName()); - } - } - - /** Write to the given task model */ - public void writeToTaskModel(TaskModelForSync task) { - if(name != null) - task.setName(name); - if(notes != null) - task.setNotes(notes); - else - task.setNotes(""); - if(importance != null) - task.setImportance(importance); - if(progressPercentage != null) - task.setProgressPercentage(progressPercentage); - if(creationDate != null) - task.setCreationDate(creationDate); - if(completionDate != null) - task.setCompletionDate(completionDate); - - // date handling: if sync service only supports one type of due date, - // we have to figure out which field to write to based on what - // already has data - - if(dueDate != null) { - if(task.getDefiniteDueDate() != null) - task.setDefiniteDueDate(dueDate); - else if(task.getPreferredDueDate() != null) - task.setPreferredDueDate(dueDate); - else - task.setDefiniteDueDate(dueDate); - } else { - task.setDefiniteDueDate(definiteDueDate); - task.setPreferredDueDate(preferredDueDate); - } - - if(hiddenUntil != null) - task.setHiddenUntil(hiddenUntil); - task.setEstimatedSeconds(estimatedSeconds); - if(elapsedSeconds != null) - task.setElapsedSeconds(elapsedSeconds); - if(syncOnComplete != null) - task.setFlags(task.getFlags() | TaskModelForSync.FLAG_SYNC_ON_COMPLETE); - else - task.setFlags(task.getFlags() & ~TaskModelForSync.FLAG_SYNC_ON_COMPLETE); - - // this is inaccurate. =/ - if(repeatInfo != null) { - if(repeatInfo == NO_REPEAT_SET) - task.setRepeat(null); - else - task.setRepeat(repeatInfo); - } - } -}