From 42dcb79f14761296eb7885c41adf3d2becb46cc0 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Wed, 29 Sep 2010 14:40:02 -0700 Subject: [PATCH] Added sync background service --- .../astrid/sync/SyncBackgroundService.java | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/com/todoroo/astrid/sync/SyncBackgroundService.java diff --git a/src/com/todoroo/astrid/sync/SyncBackgroundService.java b/src/com/todoroo/astrid/sync/SyncBackgroundService.java new file mode 100644 index 0000000..fb8fbb4 --- /dev/null +++ b/src/com/todoroo/astrid/sync/SyncBackgroundService.java @@ -0,0 +1,150 @@ +package com.todoroo.astrid.sync; + +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; + +/** + * 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 SyncBackgroundService extends Service { + + /** Minimum time before an auto-sync */ + private static final long AUTO_SYNC_MIN_OFFSET = 5*60*1000L; + + /** alarm identifier */ + public static final String SYNC_ACTION = "sync"; //$NON-NLS-1$ + + @Autowired private ExceptionService exceptionService; + + // --- abstract methods + + abstract protected SyncProvider getSyncProvider(); + + abstract protected SyncProviderUtilities getSyncUtilities(); + + // --- implementation + + public SyncBackgroundService() { + DependencyInjectionService.getInstance().inject(this); + } + + /** Receive the alarm - start the synchronize service! */ + @Override + public void onStart(Intent intent, int startId) { + try { + if(intent != null && SYNC_ACTION.equals(intent.getAction())) + startSynchronization(this); + } catch (Exception e) { + exceptionService.reportError(getSyncUtilities().getIdentifier() + "-bg-sync", e); //$NON-NLS-1$ + } + } + + /** Start the actual synchronization */ + private void startSynchronization(Context context) { + if(context == null || context.getResources() == null) + return; + + ContextManager.setContext(context); + + if(!getSyncUtilities().isLoggedIn()) + return; + + getSyncProvider().synchronize(context); + } + + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + // --- alarm management + + /** + * Schedules repeating alarm for auto-synchronization + */ + public void scheduleService() { + int syncFrequencySeconds = Preferences.getIntegerFromString( + getSyncUtilities().getSyncIntervalKey(), -1); + 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, 0, + 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, 0, + createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT); + am.cancel(pendingIntent); + } + + /** Create the alarm intent */ + private Intent createAlarmIntent(Context context) { + Intent intent = new Intent(context, getClass()); + intent.setAction(SYNC_ACTION); + 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; + } + + +}