diff --git a/api/src/com/todoroo/astrid/sync/SyncResultCallback.java b/api/src/com/todoroo/astrid/sync/SyncResultCallback.java new file mode 100644 index 000000000..e50d7d5c5 --- /dev/null +++ b/api/src/com/todoroo/astrid/sync/SyncResultCallback.java @@ -0,0 +1,25 @@ +package com.todoroo.astrid.sync; + +public interface SyncResultCallback { + /** + * Increment max sync progress + * @param incrementBy + */ + public void incrementMax(int incrementBy); + + /** + * Increment current sync progress + * @param incrementBy + */ + public void incrementProgress(int incrementBy); + + /** + * Provider started sync + */ + public void started(); + + /** + * Provider finished sync + */ + public void finished(); +} \ No newline at end of file diff --git a/astrid/src/com/todoroo/astrid/helper/SyncResultCallbackAdapter.java b/api/src/com/todoroo/astrid/sync/SyncResultCallbackAdapter.java similarity index 86% rename from astrid/src/com/todoroo/astrid/helper/SyncResultCallbackAdapter.java rename to api/src/com/todoroo/astrid/sync/SyncResultCallbackAdapter.java index a7f1ff229..29a95b34c 100644 --- a/astrid/src/com/todoroo/astrid/helper/SyncResultCallbackAdapter.java +++ b/api/src/com/todoroo/astrid/sync/SyncResultCallbackAdapter.java @@ -1,6 +1,6 @@ -package com.todoroo.astrid.helper; +package com.todoroo.astrid.sync; + -import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback; /** diff --git a/api/src/com/todoroo/astrid/sync/SyncV2BackgroundService.java b/api/src/com/todoroo/astrid/sync/SyncV2BackgroundService.java new file mode 100644 index 000000000..7c839017d --- /dev/null +++ b/api/src/com/todoroo/astrid/sync/SyncV2BackgroundService.java @@ -0,0 +1,166 @@ +package com.todoroo.astrid.sync; + +import java.util.concurrent.atomic.AtomicBoolean; + +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.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.ContextManager; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.service.ExceptionService; +import com.todoroo.andlib.utility.DateUtilities; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.api.AstridApiConstants; + +/** + * Performs synchronization service logic in background service to avoid + * ANR (application not responding) messages. + *

+ * Starting this service + * schedules a repeating alarm which handles + * synchronization with your serv + * + * @author Tim Su + * + */ +abstract public class SyncV2BackgroundService extends Service { + + /** Minimum time before an auto-sync */ + private static final long AUTO_SYNC_MIN_OFFSET = 5*60*1000L; + + @Autowired private ExceptionService exceptionService; + + // --- abstract methods + + abstract protected SyncV2Provider getSyncProvider(); + + abstract protected SyncProviderUtilities getSyncUtilities(); + + // --- implementation + + public SyncV2BackgroundService() { + DependencyInjectionService.getInstance().inject(this); + } + + private final AtomicBoolean started = new AtomicBoolean(false); + + /** Receive the alarm - start the synchronize service! */ + @Override + public void onStart(Intent intent, int startId) { + try { + if(intent != null && !started.getAndSet(true)) { + startSynchronization(this); + } + } catch (Exception e) { + exceptionService.reportError(getSyncUtilities().getIdentifier() + "-bg-sync", e); //$NON-NLS-1$ + } + } + + /** Start the actual synchronization */ + private void startSynchronization(final Context context) { + if(context == null || context.getResources() == null) + return; + + ContextManager.setContext(context); + + if(!getSyncUtilities().isLoggedIn()) + return; + + getSyncProvider().synchronizeActiveTasks(false, new SyncResultCallbackAdapter() { + @Override + public void finished() { + getSyncUtilities().recordSuccessfulSync(); + context.sendBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH)); + } + }); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public synchronized void stop() { + started.set(false); + stopSelf(); + } + + // --- alarm management + + /** + * Schedules repeating alarm for auto-synchronization + */ + public void scheduleService() { + int syncFrequencySeconds = 0; + try { + syncFrequencySeconds = Preferences.getIntegerFromString( + getSyncUtilities().getSyncIntervalKey(), -1); + } catch(ClassCastException e) { + Preferences.setStringFromInteger(getSyncUtilities().getSyncIntervalKey(), 0); + } + Context context = ContextManager.getContext(); + if(syncFrequencySeconds <= 0) { + unscheduleService(context); + return; + } + + // figure out synchronization frequency + long interval = 1000L * syncFrequencySeconds; + long offset = computeNextSyncOffset(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, getSyncUtilities().getSyncIntervalKey(), + createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT); + + Log.i("Astrid", "Autosync set for " + offset / 1000 //$NON-NLS-1$ //$NON-NLS-2$ + + " seconds repeating every " + syncFrequencySeconds); //$NON-NLS-1$ + + // cancel all existing + am.cancel(pendingIntent); + + // schedule new + am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + offset, + interval, pendingIntent); + } + + + /** + * Removes repeating alarm for auto-synchronization + */ + private void unscheduleService(Context context) { + AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + PendingIntent pendingIntent = PendingIntent.getService(context, getSyncUtilities().getSyncIntervalKey(), + createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT); + am.cancel(pendingIntent); + } + + /** Create the alarm intent */ + private Intent createAlarmIntent(Context context) { + Intent intent = new Intent(context, getClass()); + return intent; + } + + // --- utility methods + + private long computeNextSyncOffset(long interval) { + // figure out last synchronize time + long lastSyncDate = getSyncUtilities().getLastSyncDate(); + + // if user never synchronized, give them a full offset period before bg sync + if(lastSyncDate != 0) + return Math.max(0, lastSyncDate + interval - DateUtilities.now()); + else + return interval; + } + + +} diff --git a/api/src/com/todoroo/astrid/sync/SyncV2Provider.java b/api/src/com/todoroo/astrid/sync/SyncV2Provider.java new file mode 100644 index 000000000..246d2b776 --- /dev/null +++ b/api/src/com/todoroo/astrid/sync/SyncV2Provider.java @@ -0,0 +1,83 @@ +package com.todoroo.astrid.sync; + +import java.io.IOException; + +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.service.ExceptionService; + + +abstract public class SyncV2Provider { + + public class SyncExceptionHandler { + public void handleException(String tag, Exception e) { + //TODO: When Crittercism supports it, report error to them + getUtilities().setLastError(e.toString()); + + // occurs when application was closed + if(e instanceof IllegalStateException) { + exceptionService.reportError(tag + "-caught", e); //$NON-NLS-1$ + } + + // occurs when network error + else if(e instanceof IOException) { + exceptionService.reportError(tag + "-io", e); //$NON-NLS-1$ + } + + // unhandled error + else { + exceptionService.reportError(tag + "-unhandled", e); //$NON-NLS-1$ + } + } + } + + @Autowired + protected ExceptionService exceptionService; + + protected final SyncExceptionHandler handler; + + public SyncV2Provider() { + DependencyInjectionService.getInstance().inject(this); + handler = new SyncExceptionHandler(); + } + + /** + * @return sync provider name (displayed in sync menu) + */ + abstract public String getName(); + + /** + * @return true if this provider is logged in + */ + abstract public boolean isActive(); + + /** + * Synchronize all of user's active tasks + * @param manual whether manually triggered + * @param callback callback object + */ + abstract public void synchronizeActiveTasks(boolean manual, SyncResultCallback callback); + + /** + * Synchronize a single list + * @param list object representing list (TaskListActivity-dependent) + * @param manual whether was manually triggered + * @param callback callback object + */ + abstract public void synchronizeList(Object list, boolean manual, SyncResultCallback callback); + + /** + * Sign out of service, deleting all synchronization metadata + */ + abstract public void signOut(); + + /** + * @return sync utility instance + */ + abstract protected SyncProviderUtilities getUtilities(); + + @Override + public String toString() { + return getName(); + } +} diff --git a/astrid/plugin-src/com/timsu/astrid/C2DMReceiver.java b/astrid/plugin-src/com/timsu/astrid/C2DMReceiver.java index cb177186b..eb27171fd 100644 --- a/astrid/plugin-src/com/timsu/astrid/C2DMReceiver.java +++ b/astrid/plugin-src/com/timsu/astrid/C2DMReceiver.java @@ -40,11 +40,11 @@ import com.todoroo.astrid.dao.UpdateDao; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Update; -import com.todoroo.astrid.helper.SyncResultCallbackAdapter; import com.todoroo.astrid.reminders.Notifications; import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.service.TaskService; +import com.todoroo.astrid.sync.SyncResultCallbackAdapter; import com.todoroo.astrid.tags.TagFilterExposer; import com.todoroo.astrid.utility.Constants; import com.todoroo.astrid.utility.Flags; diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmBackgroundService.java b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmBackgroundService.java index ccfbe7f66..761ac046d 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmBackgroundService.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmBackgroundService.java @@ -3,11 +3,11 @@ package com.todoroo.astrid.actfm; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; -import com.todoroo.astrid.actfm.sync.ActFmSyncProvider; +import com.todoroo.astrid.actfm.sync.ActFmSyncV2Provider; import com.todoroo.astrid.service.StatisticsService; -import com.todoroo.astrid.sync.SyncBackgroundService; -import com.todoroo.astrid.sync.SyncProvider; import com.todoroo.astrid.sync.SyncProviderUtilities; +import com.todoroo.astrid.sync.SyncV2BackgroundService; +import com.todoroo.astrid.sync.SyncV2Provider; /** * SynchronizationService is the service that performs Astrid's background @@ -17,7 +17,7 @@ import com.todoroo.astrid.sync.SyncProviderUtilities; * @author Tim Su * */ -public class ActFmBackgroundService extends SyncBackgroundService { +public class ActFmBackgroundService extends SyncV2BackgroundService { @Autowired ActFmPreferenceService actFmPreferenceService; @@ -26,8 +26,8 @@ public class ActFmBackgroundService extends SyncBackgroundService { } @Override - protected SyncProvider getSyncProvider() { - return new ActFmSyncProvider(); + protected SyncV2Provider getSyncProvider() { + return new ActFmSyncV2Provider(); } @Override diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java index 2c2435add..0dbd9fcbe 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java @@ -77,12 +77,12 @@ import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.activity.Eula; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.gtasks.auth.ModernAuthManager; -import com.todoroo.astrid.helper.SyncResultCallbackAdapter; import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; import com.todoroo.astrid.service.SyncV2Service; import com.todoroo.astrid.service.TaskService; +import com.todoroo.astrid.sync.SyncResultCallbackAdapter; /** * This activity allows users to sign in or log in to Astrid.com diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmPreferences.java b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmPreferences.java index c44221bfc..27834e7eb 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmPreferences.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmPreferences.java @@ -1,14 +1,18 @@ package com.todoroo.astrid.actfm; +import android.content.Intent; import android.content.res.Resources; import android.preference.Preference; import com.timsu.astrid.R; import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.ContextManager; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; -import com.todoroo.astrid.actfm.sync.ActFmSyncProvider; +import com.todoroo.astrid.actfm.sync.ActFmSyncV2Provider; +import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.sync.SyncProviderPreferences; import com.todoroo.astrid.sync.SyncProviderUtilities; +import com.todoroo.astrid.sync.SyncResultCallbackAdapter; /** * Displays synchronization preferences and an action panel so users can @@ -28,13 +32,23 @@ public class ActFmPreferences extends SyncProviderPreferences { @Override public void startSync() { - new ActFmSyncProvider().synchronize(this); - finish(); + if (!actFmPreferenceService.isLoggedIn()) { + Intent intent = new Intent(this, ActFmLoginActivity.class); + startActivityForResult(intent, 0); + } else { + new ActFmSyncV2Provider().synchronizeActiveTasks(true, new SyncResultCallbackAdapter() { + @Override + public void finished() { + ContextManager.getContext().sendBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH)); + } + }); + finish(); + } } @Override public void logOut() { - new ActFmSyncProvider().signOut(); + new ActFmSyncV2Provider().signOut(); } @Override diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java index b84b836d5..1a41668c7 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java @@ -59,6 +59,7 @@ import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.service.TaskService; +import com.todoroo.astrid.sync.SyncV2Provider.SyncExceptionHandler; import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.utility.Flags; @@ -583,7 +584,7 @@ public final class ActFmSyncService { * Fetch tagData listing asynchronously */ public void fetchTagDataDashboard(boolean manual, final Runnable done) { - invokeFetchList("goal", manual, new ListItemProcessor() { + invokeFetchList("goal", manual, null, new ListItemProcessor() { @Override protected void mergeAndSave(JSONArray list, HashMap locals) throws JSONException { TagData remote = new TagData(); @@ -686,8 +687,8 @@ public final class ActFmSyncService { * @param manual * @param done */ - public void fetchActiveTasks(final boolean manual, Runnable done) { - invokeFetchList("task", manual, new ListItemProcessor() { + public void fetchActiveTasks(final boolean manual, SyncExceptionHandler handler, Runnable done) { + invokeFetchList("task", manual, handler, new ListItemProcessor() { @Override protected void mergeAndSave(JSONArray list, HashMap locals) throws JSONException { Task remote = new Task(); @@ -733,7 +734,7 @@ public final class ActFmSyncService { * @param done */ public void fetchTasksForTag(final TagData tagData, final boolean manual, Runnable done) { - invokeFetchList("task", manual, new ListItemProcessor() { + invokeFetchList("task", manual, null, new ListItemProcessor() { @Override protected void mergeAndSave(JSONArray list, HashMap locals) throws JSONException { Task remote = new Task(); @@ -782,7 +783,7 @@ public final class ActFmSyncService { * @param done */ public void fetchUpdatesForTag(final TagData tagData, final boolean manual, Runnable done) { - invokeFetchList("activity", manual, new UpdateListItemProcessor(), done, + invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done, "updates:" + tagData.getId(), "tag_id", tagData.getValue(TagData.REMOTE_ID)); } @@ -793,7 +794,7 @@ public final class ActFmSyncService { * @param runnable */ public void fetchUpdatesForTask(final Task task, boolean manual, Runnable done) { - invokeFetchList("activity", manual, new UpdateListItemProcessor(), done, + invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done, "comments:" + task.getId(), "task_id", task.getValue(Task.REMOTE_ID)); } @@ -803,7 +804,7 @@ public final class ActFmSyncService { * @param done */ public void fetchPersonalUpdates(boolean manual, Runnable done) { - invokeFetchList("activity", manual, new UpdateListItemProcessor(), done, "personal"); + invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done, "personal"); } private class UpdateListItemProcessor extends ListItemProcessor { @@ -931,7 +932,7 @@ public final class ActFmSyncService { } /** Call sync method */ - private void invokeFetchList(final String model, final boolean manual, + private void invokeFetchList(final String model, final boolean manual, final SyncExceptionHandler handler, final ListItemProcessor processor, final Runnable done, final String lastSyncKey, Object... params) { if(!checkForToken()) @@ -955,7 +956,10 @@ public final class ActFmSyncService { if(done != null) done.run(); } catch (IOException e) { - handleException("io-exception-list-" + model, e); + if (handler != null) + handler.handleException("io-exception-list-" + model, e); + else + handleException("io-exception-list-" + model, e); } catch (JSONException e) { handleException("json: " + result.toString(), e); } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java index c4844789b..0aedd5480 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java @@ -8,12 +8,11 @@ import java.util.concurrent.atomic.AtomicInteger; import org.json.JSONException; +import com.timsu.astrid.C2DMReceiver; import com.timsu.astrid.R; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.ContextManager; -import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.andlib.service.ExceptionService; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.Preferences; @@ -22,9 +21,9 @@ import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.StartupService; -import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback; -import com.todoroo.astrid.service.SyncV2Service.SyncV2Provider; import com.todoroo.astrid.service.TaskService; +import com.todoroo.astrid.sync.SyncResultCallback; +import com.todoroo.astrid.sync.SyncV2Provider; import com.todoroo.astrid.tags.TagService; /** @@ -37,23 +36,29 @@ public class ActFmSyncV2Provider extends SyncV2Provider { @Autowired ActFmSyncService actFmSyncService; - @Autowired ExceptionService exceptionService; - @Autowired TaskService taskService; static { AstridDependencyInjector.initialize(); } - public ActFmSyncV2Provider() { - DependencyInjectionService.getInstance().inject(this); - } - @Override public String getName() { return ContextManager.getString(R.string.actfm_APr_header); } + @Override + public ActFmPreferenceService getUtilities() { + return actFmPreferenceService; + } + + @Override + public void signOut() { + actFmPreferenceService.setToken(null); + actFmPreferenceService.clearLastSyncDate(); + C2DMReceiver.unregister(); + } + @Override public boolean isActive() { return actFmPreferenceService.isLoggedIn(); @@ -90,13 +95,15 @@ public class ActFmSyncV2Provider extends SyncV2Provider { time = actFmSyncService.fetchTags(time); Preferences.setInt(LAST_TAG_FETCH_TIME, time); } catch (JSONException e) { - exceptionService.reportError("actfm-sync", e); //$NON-NLS-1$ + handler.handleException("actfm-sync", e); //$NON-NLS-1$ } catch (IOException e) { - exceptionService.reportError("actfm-sync", e); //$NON-NLS-1$ + handler.handleException("actfm-sync", e); //$NON-NLS-1$ } finally { callback.incrementProgress(20); - if(finisher.decrementAndGet() == 0) + if(finisher.decrementAndGet() == 0) { + actFmPreferenceService.recordSuccessfulSync(); callback.finished(); + } } } }).start(); @@ -105,14 +112,16 @@ public class ActFmSyncV2Provider extends SyncV2Provider { /** @return runnable to fetch changes to tags */ private void startTaskFetcher(final boolean manual, final SyncResultCallback callback, final AtomicInteger finisher) { - actFmSyncService.fetchActiveTasks(manual, new Runnable() { + actFmSyncService.fetchActiveTasks(manual, handler, new Runnable() { @Override public void run() { pushQueued(callback, finisher); callback.incrementProgress(30); - if(finisher.decrementAndGet() == 0) + if(finisher.decrementAndGet() == 0) { + actFmPreferenceService.recordSuccessfulSync(); callback.finished(); + } } }); } @@ -141,8 +150,10 @@ public class ActFmSyncV2Provider extends SyncV2Provider { actFmSyncService.pushTaskOnSave(task, task.getMergedValues()); } finally { callback.incrementProgress(20); - if(finisher.decrementAndGet() == 0) + if(finisher.decrementAndGet() == 0) { + actFmPreferenceService.recordSuccessfulSync(); callback.finished(); + } } } }).start(); diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksBackgroundService.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksBackgroundService.java index caadda2bb..be65cd9d7 100644 --- a/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksBackgroundService.java +++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksBackgroundService.java @@ -2,19 +2,19 @@ package com.todoroo.astrid.gtasks; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.astrid.gtasks.sync.GtasksSyncProvider; +import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider; import com.todoroo.astrid.service.StatisticsService; -import com.todoroo.astrid.sync.SyncBackgroundService; -import com.todoroo.astrid.sync.SyncProvider; import com.todoroo.astrid.sync.SyncProviderUtilities; +import com.todoroo.astrid.sync.SyncV2BackgroundService; +import com.todoroo.astrid.sync.SyncV2Provider; -public class GtasksBackgroundService extends SyncBackgroundService { +public class GtasksBackgroundService extends SyncV2BackgroundService { @Autowired private GtasksPreferenceService gtasksPreferenceService; @Override - protected SyncProvider getSyncProvider() { - return new GtasksSyncProvider(); + protected SyncV2Provider getSyncProvider() { + return new GtasksSyncV2Provider(); } @Override diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksPreferences.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksPreferences.java index 6d8be9062..456d180c8 100644 --- a/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksPreferences.java +++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksPreferences.java @@ -1,13 +1,18 @@ package com.todoroo.astrid.gtasks; +import android.content.Intent; import android.os.Bundle; import com.timsu.astrid.R; import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.astrid.gtasks.sync.GtasksSyncProvider; +import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; +import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider; import com.todoroo.astrid.sync.SyncProviderPreferences; import com.todoroo.astrid.sync.SyncProviderUtilities; +import com.todoroo.astrid.sync.SyncResultCallbackAdapter; /** * Displays synchronization preferences and an action panel so users can @@ -37,13 +42,23 @@ public class GtasksPreferences extends SyncProviderPreferences { @Override public void startSync() { - new GtasksSyncProvider().synchronize(this); - finish(); + if (!gtasksPreferenceService.isLoggedIn()) { + Intent intent = new Intent(this, GtasksLoginActivity.class); + startActivityForResult(intent, 0); + } else { + new GtasksSyncV2Provider().synchronizeActiveTasks(true, new SyncResultCallbackAdapter() { + @Override + public void finished() { + ContextManager.getContext().sendBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH)); + } + }); + finish(); + } } @Override public void logOut() { - new GtasksSyncProvider().signOut(); + new GtasksSyncV2Provider().signOut(); } @Override diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java index 1637bfcde..c98f877a4 100644 --- a/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.java @@ -50,10 +50,10 @@ import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.api.GtasksInvoker; -import com.todoroo.astrid.helper.SyncResultCallbackAdapter; import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.StatisticsService; import com.todoroo.astrid.service.SyncV2Service; +import com.todoroo.astrid.sync.SyncResultCallbackAdapter; /** * This activity allows users to sign in or log in to Google Tasks diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncV2Provider.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncV2Provider.java index 010134151..759575600 100644 --- a/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncV2Provider.java +++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncV2Provider.java @@ -16,11 +16,11 @@ import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.ContextManager; -import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.DateUtilities; +import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; import com.todoroo.astrid.dao.StoreObjectDao; @@ -41,9 +41,9 @@ import com.todoroo.astrid.gtasks.auth.GtasksTokenValidator; import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; -import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback; -import com.todoroo.astrid.service.SyncV2Service.SyncV2Provider; import com.todoroo.astrid.service.TaskService; +import com.todoroo.astrid.sync.SyncResultCallback; +import com.todoroo.astrid.sync.SyncV2Provider; import com.todoroo.astrid.utility.Flags; public class GtasksSyncV2Provider extends SyncV2Provider { @@ -60,15 +60,24 @@ public class GtasksSyncV2Provider extends SyncV2Provider { AstridDependencyInjector.initialize(); } - public GtasksSyncV2Provider() { - DependencyInjectionService.getInstance().inject(this); - } - @Override public String getName() { return ContextManager.getString(R.string.gtasks_GPr_header); } + @Override + public GtasksPreferenceService getUtilities() { + return gtasksPreferenceService; + } + + @Override + public void signOut() { + gtasksPreferenceService.clearLastSyncDate(); + gtasksPreferenceService.setToken(null); + Preferences.setString(GtasksPreferenceService.PREF_USER_NAME, null); + gtasksMetadataService.clearMetadata(); + } + @Override public boolean isActive() { return gtasksPreferenceService.isLoggedIn(); @@ -88,7 +97,7 @@ public class GtasksSyncV2Provider extends SyncV2Provider { try { gtasksListService.updateLists(invoker.allGtaskLists()); } catch (IOException e) { - // error updating lists + handler.handleException("gtasks-sync=io", e); //$NON-NLS-1$ } finally { callback.incrementMax(25); } @@ -101,8 +110,9 @@ public class GtasksSyncV2Provider extends SyncV2Provider { new Thread(new Runnable() { @Override public void run() { - synchronizeListHelper(list, invoker, callback); + synchronizeListHelper(list, invoker, handler, callback); if (finisher.decrementAndGet() == 0) { + gtasksPreferenceService.recordSuccessfulSync(); callback.finished(); } } @@ -126,7 +136,7 @@ public class GtasksSyncV2Provider extends SyncV2Provider { try { gtasksSyncService.pushTaskOnSave(task, task.getMergedValues(), invoker, false); } catch (IOException e) { - // Eh + handler.handleException("gtasks-sync-io", e); //$NON-NLS-1$ } finally { callback.incrementProgress(10); } @@ -156,7 +166,7 @@ public class GtasksSyncV2Provider extends SyncV2Provider { String authToken = getValidatedAuthToken(); callback.incrementProgress(25); final GtasksInvoker service = new GtasksInvoker(authToken); - synchronizeListHelper(gtasksList, service, callback); + synchronizeListHelper(gtasksList, service, null, callback); } finally { callback.incrementProgress(25); callback.finished(); @@ -178,7 +188,7 @@ public class GtasksSyncV2Provider extends SyncV2Provider { } - private void synchronizeListHelper(StoreObject list, GtasksInvoker invoker, SyncResultCallback callback) { + private void synchronizeListHelper(StoreObject list, GtasksInvoker invoker, SyncExceptionHandler handler, SyncResultCallback callback) { // Do stuff String listId = list.getValue(GtasksList.REMOTE_ID); long lastSyncDate; @@ -208,7 +218,8 @@ public class GtasksSyncV2Provider extends SyncV2Provider { gtasksTaskListUpdater.correctOrderAndIndentForList(listId); } } catch (IOException e) { - // Stuff + if (handler != null) + handler.handleException("gtasks-sync-io", e); //$NON-NLS-1$ } } diff --git a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java index a2b7cf3cf..971fd596a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java @@ -59,7 +59,7 @@ import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; -import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback; +import com.todoroo.astrid.sync.SyncResultCallback; import com.todoroo.astrid.timers.TimerActionControlSet.TimerActionListener; import com.todoroo.astrid.utility.Flags; diff --git a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java index ad3862552..e4773e6fb 100644 --- a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java +++ b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java @@ -6,6 +6,7 @@ import com.todoroo.astrid.sync.SyncBackgroundService; import com.todoroo.astrid.sync.SyncProvider; import com.todoroo.astrid.sync.SyncProviderUtilities; + /** * SynchronizationService is the service that performs Astrid's background * synchronization with online task managers. Starting this service diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java index e32b41f21..a3e0eb2c6 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java @@ -109,11 +109,11 @@ import com.todoroo.astrid.service.StartupService; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; import com.todoroo.astrid.service.SyncV2Service; -import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback; -import com.todoroo.astrid.service.SyncV2Service.SyncV2Provider; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.service.UpgradeService; +import com.todoroo.astrid.sync.SyncResultCallback; +import com.todoroo.astrid.sync.SyncV2Provider; import com.todoroo.astrid.ui.DateChangedAlerts; import com.todoroo.astrid.utility.AstridPreferences; import com.todoroo.astrid.utility.Constants; diff --git a/astrid/src/com/todoroo/astrid/helper/ProgressBarSyncResultCallback.java b/astrid/src/com/todoroo/astrid/helper/ProgressBarSyncResultCallback.java index 222d85775..625d59ac3 100644 --- a/astrid/src/com/todoroo/astrid/helper/ProgressBarSyncResultCallback.java +++ b/astrid/src/com/todoroo/astrid/helper/ProgressBarSyncResultCallback.java @@ -8,6 +8,7 @@ import android.view.animation.AlphaAnimation; import android.widget.ProgressBar; import com.todoroo.andlib.utility.AndroidUtilities; +import com.todoroo.astrid.sync.SyncResultCallbackAdapter; public class ProgressBarSyncResultCallback extends SyncResultCallbackAdapter { diff --git a/astrid/src/com/todoroo/astrid/service/SyncV2Service.java b/astrid/src/com/todoroo/astrid/service/SyncV2Service.java index a0a975f5e..2b8af7a16 100644 --- a/astrid/src/com/todoroo/astrid/service/SyncV2Service.java +++ b/astrid/src/com/todoroo/astrid/service/SyncV2Service.java @@ -6,6 +6,8 @@ import java.util.List; import com.todoroo.astrid.actfm.sync.ActFmSyncV2Provider; import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider; +import com.todoroo.astrid.sync.SyncResultCallback; +import com.todoroo.astrid.sync.SyncV2Provider; /** * SyncV2Service is a simplified synchronization interface for supporting @@ -16,62 +18,6 @@ import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider; */ public class SyncV2Service { - public interface SyncResultCallback { - /** - * Increment max sync progress - * @param incrementBy - */ - public void incrementMax(int incrementBy); - - /** - * Increment current sync progress - * @param incrementBy - */ - public void incrementProgress(int incrementBy); - - /** - * Provider started sync - */ - public void started(); - - /** - * Provider finished sync - */ - public void finished(); - } - - abstract public static class SyncV2Provider { - /** - * @return sync provider name (displayed in sync menu) - */ - abstract public String getName(); - - /** - * @return true if this provider is logged in - */ - abstract public boolean isActive(); - - /** - * Synchronize all of user's active tasks - * @param manual whether manually triggered - * @param callback callback object - */ - abstract public void synchronizeActiveTasks(boolean manual, SyncResultCallback callback); - - /** - * Synchronize a single list - * @param list object representing list (TaskListActivity-dependent) - * @param manual whether was manually triggered - * @param callback callback object - */ - abstract public void synchronizeList(Object list, boolean manual, SyncResultCallback callback); - - @Override - public String toString() { - return getName(); - } - } - /* * At present, sync provider interactions are handled through code. If * there is enough interest, the Astrid team could create an interface