Added background synchronization for RTM

pull/14/head
Tim Su 14 years ago
parent 6689788047
commit 8f80a9a6c5

@ -4,7 +4,7 @@
<classpathentry kind="src" path="src-legacy"/>
<classpathentry kind="src" path="api-src"/>
<classpathentry kind="src" path="common-src"/>
<classpathentry excluding="com/todoroo/astrid/rmilk/EditOperationExposer.java|com/todoroo/astrid/rmilk/MilkEditActivity.java|com/todoroo/astrid/rmilk/StartupReceiver.java|com/todoroo/astrid/backup/TasksXmlExporter.java|com/todoroo/astrid/backup/TasksXmlImporter.java" kind="src" path="plugin-src"/>
<classpathentry excluding="com/todoroo/astrid/rmilk/EditOperationExposer.java|com/todoroo/astrid/rmilk/MilkEditActivity.java|com/todoroo/astrid/backup/TasksXmlExporter.java|com/todoroo/astrid/backup/TasksXmlImporter.java" kind="src" path="plugin-src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="lib" path="lib/commons-codec-1.3.jar"/>

@ -240,7 +240,7 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver android:name="com.todoroo.astrid.reminders.ReminderStartupService">
<receiver android:name="com.todoroo.astrid.reminders.ReminderStartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
@ -269,7 +269,14 @@
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<service android:name="com.todoroo.astrid.rmilk.MilkBackgroundService"/>
<receiver android:name="com.todoroo.astrid.rmilk.MilkStartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</manifest>

@ -28,6 +28,11 @@ abstract public class TodorooPreferences extends PreferenceActivity {
public abstract int getPreferenceResource();
/**
* Update preferences for the given preference
* @param preference
* @param value setting. may be null.
*/
public abstract void updatePreferences(Preference preference, Object value);
// --- implementation
@ -57,8 +62,7 @@ abstract public class TodorooPreferences extends PreferenceActivity {
else if(preference instanceof RingtonePreference)
value = getPreferenceManager().getSharedPreferences().getString(preference.getKey(), null);
if(value != null || Preference.class.equals(preference.getClass()))
updatePreferences(preference, value);
updatePreferences(preference, value);
preference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference myPreference, Object newValue) {

@ -13,7 +13,7 @@ import com.todoroo.astrid.service.AstridDependencyInjector;
* @author Tim Su <tim@todoroo.com>
*
*/
public class ReminderStartupService extends BroadcastReceiver {
public class ReminderStartupReceiver extends BroadcastReceiver {
static {
AstridDependencyInjector.initialize();

@ -0,0 +1,125 @@
package com.todoroo.astrid.rmilk;
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.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
import com.todoroo.astrid.utility.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 MilkBackgroundService extends Service {
/** Minimum 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"; //$NON-NLS-1$
// --- BroadcastReceiver abstract methods
/** Receive the alarm - start the synchronize service! */
@Override
public void onStart(Intent intent, int startId) {
if(SYNC_ACTION.equals(intent.getAction()))
startSynchronization(this);
}
/** Start the actual synchronization */
private void startSynchronization(Context context) {
if(context == null || context.getResources() == null)
return;
if(MilkUtilities.isOngoing())
return;
new RTMSyncProvider().synchronize(context);
}
// --- alarm management
/**
* Schedules repeating alarm for auto-synchronization
*/
public static void scheduleService() {
Integer syncFrequencySeconds = Preferences.getIntegerFromString(R.string.rmilk_MPr_interval_key);
Context context = ContextManager.getContext();
if(syncFrequencySeconds == null) {
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 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, MilkBackgroundService.class);
intent.setAction(SYNC_ACTION);
return intent;
}
// --- utility methods
private static long computeNextSyncOffset(long interval) {
// figure out last synchronize time
long lastSyncDate = MilkUtilities.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;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

@ -31,7 +31,7 @@ public class MilkDetailExposer extends BroadcastReceiver implements DetailExpose
@Override
public void onReceive(Context context, Intent intent) {
// if we aren't logged in, don't expose features
if(!Utilities.isLoggedIn())
if(!MilkUtilities.isLoggedIn())
return;
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
@ -44,7 +44,7 @@ public class MilkDetailExposer extends BroadcastReceiver implements DetailExpose
return;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, Utilities.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, MilkUtilities.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
@ -90,7 +90,7 @@ public class MilkDetailExposer extends BroadcastReceiver implements DetailExpose
@Override
public String getPluginIdentifier() {
return Utilities.IDENTIFIER;
return MilkUtilities.IDENTIFIER;
}
}

@ -19,7 +19,7 @@ import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.rmilk.Utilities.ListContainer;
import com.todoroo.astrid.rmilk.MilkUtilities.ListContainer;
import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkTask;
@ -56,7 +56,7 @@ public class MilkFilterExposer extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// if we aren't logged in, don't expose features
if(!Utilities.isLoggedIn())
if(!MilkUtilities.isLoggedIn())
return;
ListContainer[] lists = MilkDataService.getInstance().getListsWithCounts();
@ -78,7 +78,7 @@ public class MilkFilterExposer extends BroadcastReceiver {
list[0] = rtmHeader;
list[1] = rtmLists;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, Utilities.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, MilkUtilities.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}

@ -3,6 +3,7 @@ package com.todoroo.astrid.rmilk;
import java.util.Date;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.content.res.Resources;
import android.graphics.Color;
@ -30,9 +31,9 @@ import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
public class MilkPreferences extends TodorooPreferences {
@Autowired
DialogUtilities dialogUtilities;
private DialogUtilities dialogUtilities;
int statusColor = Color.BLACK;
private int statusColor = Color.BLACK;
@Override
public int getPreferenceResource() {
@ -58,6 +59,12 @@ public class MilkPreferences extends TodorooPreferences {
});
}
@Override
protected void onPause() {
super.onPause();
MilkBackgroundService.scheduleService();
}
/**
*
* @param resource
@ -83,7 +90,7 @@ public class MilkPreferences extends TodorooPreferences {
// status
else if (r.getString(R.string.rmilk_MPr_status_key).equals(preference.getKey())) {
boolean loggedIn = Utilities.isLoggedIn();
boolean loggedIn = MilkUtilities.isLoggedIn();
String status;
String subtitle = ""; //$NON-NLS-1$
@ -93,47 +100,47 @@ public class MilkPreferences extends TodorooPreferences {
statusColor = Color.RED;
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
new RTMSyncProvider().synchronize(MilkPreferences.this);
startService(new Intent(MilkPreferences.this, MilkBackgroundService.class));
finish();
return true;
}
});
}
// sync is occurring
else if(Utilities.isOngoing()) {
else if(MilkUtilities.isOngoing()) {
status = r.getString(R.string.rmilk_status_ongoing);
statusColor = Color.rgb(0, 0, 100);
}
// last sync was error
else if(Utilities.getLastAttemptedSyncDate() != 0) {
else if(MilkUtilities.getLastAttemptedSyncDate() != 0) {
status = r.getString(R.string.rmilk_status_failed,
DateUtilities.getDateWithTimeFormat(MilkPreferences.this).
format(new Date(Utilities.getLastAttemptedSyncDate())));
if(Utilities.getLastSyncDate() > 0) {
format(new Date(MilkUtilities.getLastAttemptedSyncDate())));
if(MilkUtilities.getLastSyncDate() > 0) {
subtitle = r.getString(R.string.rmilk_status_failed_subtitle,
DateUtilities.getDateWithTimeFormat(MilkPreferences.this).
format(new Date(Utilities.getLastSyncDate())));
format(new Date(MilkUtilities.getLastSyncDate())));
}
statusColor = Color.rgb(100, 0, 0);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
String error = Utilities.getLastError();
String error = MilkUtilities.getLastError();
if(error != null)
dialogUtilities.okDialog(MilkPreferences.this, error, null);
return true;
}
});
} else if(Utilities.getLastSyncDate() > 0) {
} else if(MilkUtilities.getLastSyncDate() > 0) {
status = r.getString(R.string.rmilk_status_success,
DateUtilities.getDateWithTimeFormat(MilkPreferences.this).
format(new Date(Utilities.getLastSyncDate())));
format(new Date(MilkUtilities.getLastSyncDate())));
statusColor = Color.rgb(0, 100, 0);
} else {
status = r.getString(R.string.rmilk_status_never);
statusColor = Color.rgb(0, 0, 100);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
new RTMSyncProvider().synchronize(MilkPreferences.this);
startService(new Intent(MilkPreferences.this, MilkBackgroundService.class));
finish();
return true;
}
@ -149,7 +156,7 @@ public class MilkPreferences extends TodorooPreferences {
// sync button
else if (r.getString(R.string.rmilk_MPr_sync_key).equals(preference.getKey())) {
boolean loggedIn = Utilities.isLoggedIn();
boolean loggedIn = MilkUtilities.isLoggedIn();
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
new RTMSyncProvider().synchronize(MilkPreferences.this);
@ -163,7 +170,7 @@ public class MilkPreferences extends TodorooPreferences {
// log out button
else if (r.getString(R.string.rmilk_MPr_forget_key).equals(preference.getKey())) {
boolean loggedIn = Utilities.isLoggedIn();
boolean loggedIn = MilkUtilities.isLoggedIn();
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
dialogUtilities.okCancelDialog(MilkPreferences.this,

@ -0,0 +1,18 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.rmilk;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MilkStartupReceiver extends BroadcastReceiver {
@Override
/** Called when device is restarted */
public void onReceive(final Context context, Intent intent) {
MilkBackgroundService.scheduleService();
}
}

@ -13,13 +13,13 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.rmilk.data.MilkList;
/**
* Utility constants
* Constants and preferences for rtm plugin
*
* @author Tim Su <tim@todoroo.com>
*
*/
@SuppressWarnings("nls")
public class Utilities {
public class MilkUtilities {
// --- constants

@ -1,40 +0,0 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.rmilk;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
import android.preference.PreferenceManager;
import com.todoroo.astrid.R;
public class StartupReceiver extends BroadcastReceiver {
public static void setPreferenceDefaults(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Editor editor = prefs.edit();
Resources r = context.getResources();
if(!prefs.contains(r.getString(R.string.rmilk_MPr_interval_key))) {
editor.putString(r.getString(R.string.rmilk_MPr_interval_key),
Integer.toString(0));
}
if(!prefs.contains(r.getString(R.string.rmilk_MPr_shortcut_key))) {
editor.putBoolean(r.getString(R.string.rmilk_MPr_shortcut_key), true);
}
editor.commit();
}
@Override
/** Called when this plug-in run for the first time (installed, upgrade, or device was rebooted */
public void onReceive(final Context context, Intent intent) {
setPreferenceDefaults(context);
}
}

@ -29,8 +29,8 @@ import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.rmilk.Utilities;
import com.todoroo.astrid.rmilk.Utilities.ListContainer;
import com.todoroo.astrid.rmilk.MilkUtilities;
import com.todoroo.astrid.rmilk.MilkUtilities.ListContainer;
import com.todoroo.astrid.rmilk.api.data.RtmList;
import com.todoroo.astrid.rmilk.api.data.RtmLists;
import com.todoroo.astrid.rmilk.sync.RTMTaskContainer;
@ -104,7 +104,7 @@ public final class MilkDataService {
* @return null if never sync'd
*/
public TodorooCursor<Task> getLocallyUpdated(Property<?>[] properties) {
long lastSyncDate = Utilities.getLastSyncDate();
long lastSyncDate = MilkUtilities.getLastSyncDate();
if(lastSyncDate == 0)
return taskDao.query(Query.select(Task.ID).where(Criterion.none));
return

@ -36,7 +36,7 @@ import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.rmilk.MilkLoginActivity;
import com.todoroo.astrid.rmilk.MilkPreferences;
import com.todoroo.astrid.rmilk.Utilities;
import com.todoroo.astrid.rmilk.MilkUtilities;
import com.todoroo.astrid.rmilk.MilkLoginActivity.SyncLoginCallback;
import com.todoroo.astrid.rmilk.api.ApplicationInfo;
import com.todoroo.astrid.rmilk.api.ServiceImpl;
@ -84,8 +84,8 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
* Sign out of RTM, deleting all synchronization metadata
*/
public void signOut() {
Utilities.setToken(null);
Utilities.clearLastSyncDate();
MilkUtilities.setToken(null);
MilkUtilities.clearLastSyncDate();
dataService = MilkDataService.getInstance();
dataService.clearMetadata();
@ -109,7 +109,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
*/
@Override
protected void handleException(String tag, Exception e, boolean showError) {
Utilities.setLastError(e.toString());
MilkUtilities.setLastError(e.toString());
// occurs when application was closed
if(e instanceof IllegalStateException) {
@ -153,11 +153,11 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
final Resources r = context.getResources();
FlurryAgent.onEvent("rtm-started");
Utilities.recordSyncStart();
MilkUtilities.recordSyncStart();
try {
String appName = null;
String authToken = Utilities.getToken();
String authToken = MilkUtilities.getToken();
String z = stripslashes(0,"q9883o3384n21snq17501qn38oo1r689", "b");
String v = stripslashes(16,"19o2n020345219os","a");
@ -174,7 +174,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
if(rtmService != null) {
try {
String token = rtmService.completeAuthorization();
Utilities.setToken(token);
MilkUtilities.setToken(token);
performSync();
return;
@ -197,7 +197,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
try {
String token = rtmService.completeAuthorization();
Utilities.setToken(token);
MilkUtilities.setToken(token);
synchronize(context);
return null;
} catch (Exception e) {
@ -224,7 +224,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
} catch (Exception e) {
handleException("rtm-authenticate", e, true);
} finally {
Utilities.stopOngoing();
MilkUtilities.stopOngoing();
}
}
@ -243,7 +243,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
// read all tasks
ArrayList<RTMTaskContainer> remoteChanges = new ArrayList<RTMTaskContainer>();
Date lastSyncDate = new Date(Utilities.getLastSyncDate());
Date lastSyncDate = new Date(MilkUtilities.getLastSyncDate());
boolean shouldSyncIndividualLists = false;
String filter = null;
if(lastSyncDate.getTime() == 0)
@ -284,7 +284,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
syncData.localUpdated.close();
}
Utilities.recordSuccessfulSync();
MilkUtilities.recordSuccessfulSync();
FlurryAgent.onEvent("rtm-sync-finished"); //$NON-NLS-1$
} catch (IllegalStateException e) {

@ -69,7 +69,7 @@
<string name="rmilk_MPr_group_options">Options</string>
<!-- Synchronization Interval Title -->
<string name="rmilk_MPr_interval_title">Synchronization Interval</string>
<string name="rmilk_MPr_interval_title">Background Sync</string>
<!-- Synchronization Interval Description (when disabled) -->
<string name="rmilk_MPr_interval_desc_disabled">Background synchronization is disabled</string>
<!-- Synchronization Interval Description (%s => setting) -->

@ -13,7 +13,7 @@
</PreferenceCategory>
<!-- PreferenceCategory
<PreferenceCategory
android:title="@string/rmilk_MPr_group_options">
<ListPreference
@ -22,7 +22,7 @@
android:entryValues="@array/rmilk_MPr_interval_values"
android:title="@string/rmilk_MPr_interval_title" />
</PreferenceCategory -->
</PreferenceCategory>
<PreferenceCategory
android:title="@string/rmilk_MPr_group_actions">

Loading…
Cancel
Save