From 5c5612746a4e753f1fc5ead761b85b012273c5a1 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Mon, 23 Aug 2010 15:33:11 -0700 Subject: [PATCH] AST-285 - rtm login page randomly comes up --- .../todoroo/astrid/common/SyncProvider.java | 79 ++++---- .../todoroo/astrid/common}/TaskContainer.java | 3 +- .../ProducteevBackgroundService.java | 3 +- .../producteev/ProducteevPreferences.java | 4 +- .../sync/ProducteevSyncProvider.java | 87 +++++---- .../sync/ProducteevTaskContainer.java | 2 +- .../astrid/rmilk/MilkBackgroundService.java | 5 +- .../todoroo/astrid/rmilk/MilkPreferences.java | 7 +- .../astrid/rmilk/sync/RTMSyncProvider.java | 177 ++++++++++-------- .../astrid/rmilk/sync/RTMTaskContainer.java | 2 +- 10 files changed, 192 insertions(+), 177 deletions(-) rename astrid/{api-src/com/todoroo/astrid/api => plugin-src/com/todoroo/astrid/common}/TaskContainer.java (91%) diff --git a/astrid/plugin-src/com/todoroo/astrid/common/SyncProvider.java b/astrid/plugin-src/com/todoroo/astrid/common/SyncProvider.java index 11477a6b0..a01b8287b 100644 --- a/astrid/plugin-src/com/todoroo/astrid/common/SyncProvider.java +++ b/astrid/plugin-src/com/todoroo/astrid/common/SyncProvider.java @@ -11,20 +11,16 @@ import java.util.HashMap; import android.app.Activity; import android.app.Notification; +import android.app.Service; import android.content.Context; import android.widget.Toast; import com.timsu.astrid.R; -import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.Property.LongProperty; -import com.todoroo.andlib.service.Autowired; -import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.andlib.service.ExceptionService; +import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.NotificationManager; -import com.todoroo.astrid.api.TaskContainer; import com.todoroo.astrid.model.Task; import com.todoroo.astrid.utility.Constants; -import com.todoroo.astrid.utility.Flags; /** * A helper class for writing synchronization services for Astrid. This class @@ -42,13 +38,23 @@ public abstract class SyncProvider { // --- abstract methods - your services should implement these /** - * Perform authenticate and other pre-synchronization steps, then - * synchronize. + * Perform log in (launching activity if necessary) and sync. This is + * invoked when users manually request synchronization * - * @param context - * either the parent activity, or a background service + * @param activity + * context + */ + abstract protected void initiateManual(Activity activity); + + /** + * Perform synchronize. Since this can be called from background services, + * you should not open up new activities. Instead, if the user is not signed + * in, your service should do nothing. + * + * @param service + * context */ - abstract protected void initiate(Context context); + abstract protected void initiateBackground(Service service); /** * Updates the text of a notification and the intent to open when tapped @@ -128,14 +134,9 @@ public abstract class SyncProvider { // --- implementation - @Autowired - private ExceptionService exceptionService; - private final Notification notification; public SyncProvider() { - DependencyInjectionService.getInstance().inject(this); - // initialize notification int icon = android.R.drawable.stat_notify_sync; long when = System.currentTimeMillis(); @@ -153,34 +154,24 @@ public abstract class SyncProvider { Toast.LENGTH_LONG).show(); } }); - } - - // display notification - updateNotification(context, notification); - final NotificationManager nm = new NotificationManager.AndroidNotificationManager(context); - nm.notify(Constants.NOTIFICATION_SYNC, notification); - - // start next step in background thread - new Thread(new Runnable() { - public void run() { - try { - initiate(context); - } finally { - nm.cancel(Constants.NOTIFICATION_SYNC); + initiateManual((Activity)context); + } else if(context instanceof Service) { + // display notification + updateNotification(context, notification); + final NotificationManager nm = new NotificationManager.AndroidNotificationManager(context); + nm.notify(Constants.NOTIFICATION_SYNC, notification); + + // start next step in background thread + new Thread(new Runnable() { + public void run() { + try { + initiateBackground((Service)context); + } finally { + nm.cancel(Constants.NOTIFICATION_SYNC); + } } - } - }).start(); - } - - // --- utilities - - /** - * 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. - */ - protected void showError(final Context context, Throwable e, String message) { - exceptionService.displayAndReportError(context, message, e); + }).start(); + } } // --- synchronization logic @@ -310,8 +301,6 @@ public abstract class SyncProvider { handleException("sync-remote-updated", e, false); //$NON-NLS-1$ } } - - Flags.set(Flags.REFRESH); } // --- helper classes diff --git a/astrid/api-src/com/todoroo/astrid/api/TaskContainer.java b/astrid/plugin-src/com/todoroo/astrid/common/TaskContainer.java similarity index 91% rename from astrid/api-src/com/todoroo/astrid/api/TaskContainer.java rename to astrid/plugin-src/com/todoroo/astrid/common/TaskContainer.java index f8ed4ef8b..a4ff29e64 100644 --- a/astrid/api-src/com/todoroo/astrid/api/TaskContainer.java +++ b/astrid/plugin-src/com/todoroo/astrid/common/TaskContainer.java @@ -1,9 +1,8 @@ -package com.todoroo.astrid.api; +package com.todoroo.astrid.common; import java.util.ArrayList; import com.todoroo.andlib.utility.AndroidUtilities; -import com.todoroo.astrid.common.SyncProvider; import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Task; diff --git a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java index 0d1a64bad..1c9c0fb7d 100644 --- a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java +++ b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevBackgroundService.java @@ -39,7 +39,8 @@ public class ProducteevBackgroundService extends Service { @Override public void onStart(Intent intent, int startId) { try { - startSynchronization(this); + if(intent != null && SYNC_ACTION.equals(intent.getAction())) + startSynchronization(this); } catch (Exception e) { PluginServices.getExceptionService().reportError("pdv-bg-sync", e); //$NON-NLS-1$ } diff --git a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java index e8321fd3d..de93da04f 100644 --- a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java +++ b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java @@ -1,6 +1,5 @@ package com.todoroo.astrid.producteev; -import android.content.Intent; import android.content.res.Resources; import android.os.Bundle; import android.preference.ListPreference; @@ -31,8 +30,7 @@ public class ProducteevPreferences extends SyncProviderPreferences { @Override public void startSync() { - startService(new Intent(ProducteevBackgroundService.SYNC_ACTION, null, - this, ProducteevBackgroundService.class)); + new ProducteevSyncProvider().synchronize(this); } @Override diff --git a/astrid/plugin-src/com/todoroo/astrid/producteev/sync/ProducteevSyncProvider.java b/astrid/plugin-src/com/todoroo/astrid/producteev/sync/ProducteevSyncProvider.java index 01477f110..950c28d78 100644 --- a/astrid/plugin-src/com/todoroo/astrid/producteev/sync/ProducteevSyncProvider.java +++ b/astrid/plugin-src/com/todoroo/astrid/producteev/sync/ProducteevSyncProvider.java @@ -15,6 +15,7 @@ import org.json.JSONObject; import android.app.Activity; import android.app.Notification; import android.app.PendingIntent; +import android.app.Service; import android.content.Context; import android.content.Intent; import android.text.TextUtils; @@ -31,11 +32,12 @@ import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.astrid.api.AstridApiConstants; -import com.todoroo.astrid.api.TaskContainer; import com.todoroo.astrid.common.SyncProvider; +import com.todoroo.astrid.common.TaskContainer; import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.StoreObject; import com.todoroo.astrid.model.Task; +import com.todoroo.astrid.producteev.ProducteevBackgroundService; import com.todoroo.astrid.producteev.ProducteevLoginActivity; import com.todoroo.astrid.producteev.ProducteevPreferences; import com.todoroo.astrid.producteev.ProducteevUtilities; @@ -75,7 +77,7 @@ public class ProducteevSyncProvider extends SyncProvider { dataService.clearMetadata(); } - // ---------------------------------------------------------------------- - // ------------------------------------------------------- authentication - // ---------------------------------------------------------------------- - /** * Deal with a synchronization exception. If requested, will show an error * to the user (unless synchronization is happening in background) @@ -109,63 +109,65 @@ public class RTMSyncProvider extends SyncProvider { * whether to display a dialog */ @Override - protected void handleException(String tag, Exception e, boolean showError) { + protected void handleException(String tag, Exception e, boolean displayError) { + final Context context = ContextManager.getContext(); MilkUtilities.setLastError(e.toString()); + String message = null; + // 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 ServiceInternalException && - ((ServiceInternalException)e).getEnclosedException() instanceof - IOException) { - Exception enclosedException = ((ServiceInternalException)e).getEnclosedException(); - exceptionService.reportError(tag + "-ioexception", enclosedException); //$NON-NLS-1$ - if(showError) { - Context context = ContextManager.getContext(); - showError(context, enclosedException, - context.getString(R.string.rmilk_ioerror)); - } + // occurs when network error + } else if(!(e instanceof ApiServiceException) && e instanceof IOException) { + message = context.getString(R.string.rmilk_ioerror); } else { - if(e instanceof ServiceInternalException) - e = ((ServiceInternalException)e).getEnclosedException(); + message = context.getString(R.string.DLG_error, e.toString()); exceptionService.reportError(tag + "-unhandled", e); //$NON-NLS-1$ - if(showError) { - Context context = ContextManager.getContext(); - showError(context, e, null); - } + } + + if(displayError && context instanceof Activity && message != null) { + dialogUtilities.okDialog((Activity)context, + message, null); } } - @Override - protected void initiate(Context context) { - dataService = MilkDataService.getInstance(); + // ---------------------------------------------------------------------- + // ------------------------------------------------------ initiating sync + // ---------------------------------------------------------------------- - // authenticate the user. this will automatically call the next step - authenticate(context); + /** + * set up service + */ + @SuppressWarnings("nls") + private void initializeService(String authToken) throws ServiceInternalException { + String appName = null; + String z = stripslashes(0,"q9883o3384n21snq17501qn38oo1r689", "b"); + String v = stripslashes(16,"19o2n020345219os","a"); + + if(authToken == null) + rtmService = new ServiceImpl(new ApplicationInfo( + z, v, appName)); + else + rtmService = new ServiceImpl(new ApplicationInfo( + z, v, appName, authToken)); } /** - * Perform authentication with RTM. Will open the SyncBrowser if necessary + * initiate sync in background */ + @Override @SuppressWarnings("nls") - private void authenticate(final Context context) { - final Resources r = context.getResources(); - FlurryAgent.onEvent("rtm-started"); - - MilkUtilities.recordSyncStart(); + protected void initiateBackground(Service service) { + dataService = MilkDataService.getInstance(); try { - String appName = null; String authToken = MilkUtilities.getToken(); - String z = stripslashes(0,"q9883o3384n21snq17501qn38oo1r689", "b"); - String v = stripslashes(16,"19o2n020345219os","a"); // check if we have a token & it works if(authToken != null) { - rtmService = new ServiceImpl(new ApplicationInfo( - z, v, appName, authToken)); + initializeService(authToken); if(!rtmService.isServiceAuthorized()) // re-do login authToken = null; } @@ -180,53 +182,17 @@ public class RTMSyncProvider extends SyncProvider { return; } catch (Exception e) { - // didn't work. do the process again. + // didn't work. } } - // open up a dialog and have the user go to browser - rtmService = new ServiceImpl(new ApplicationInfo( - z, v, appName)); - final String url = rtmService.beginAuthorization(Perms.delete); - - Intent intent = new Intent(context, MilkLoginActivity.class); - MilkLoginActivity.setCallback(new SyncLoginCallback() { - public String verifyLogin(final Handler syncLoginHandler) { - if(rtmService == null) { - return null; - } - - try { - String token = rtmService.completeAuthorization(); - MilkUtilities.setToken(token); - synchronize(context); - return null; - } catch (Exception e) { - // didn't work - exceptionService.reportError("rtm-verify-login", e); - rtmService = null; - if(e instanceof ServiceInternalException) - e = ((ServiceInternalException)e).getEnclosedException(); - return r.getString(R.string.rmilk_MLA_error, e.getMessage()); - } - } - }); - intent.putExtra(MilkLoginActivity.URL_TOKEN, url); - - if(context instanceof Activity) - ((Activity)context).startActivityForResult(intent, 0); - else { - // can't synchronize until user logs in - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - MilkUtilities.stopOngoing(); - } + // can't do anything, user not logged in } else { performSync(); } } catch (IllegalStateException e) { - // occurs when application was closed + // occurs when application was closed } catch (Exception e) { handleException("rtm-authenticate", e, true); } finally { @@ -234,11 +200,66 @@ public class RTMSyncProvider extends SyncProvider { } } + /** + * If user isn't already signed in, show sign in dialog. Else perform sync. + */ + @SuppressWarnings("nls") + @Override + protected void initiateManual(final Activity activity) { + final Resources r = activity.getResources(); + String authToken = MilkUtilities.getToken(); + MilkUtilities.stopOngoing(); + + // check if we have a token & it works + if(authToken == null) { + // open up a dialog and have the user go to browser + final String url; + try { + initializeService(null); + url = rtmService.beginAuthorization(Perms.delete); + } catch (ServiceException e) { + handleException("rmilk-auth", e, true); + return; + } + + Intent intent = new Intent(activity, MilkLoginActivity.class); + MilkLoginActivity.setCallback(new SyncLoginCallback() { + public String verifyLogin(final Handler syncLoginHandler) { + if(rtmService == null) { + return null; + } + + try { + String token = rtmService.completeAuthorization(); + MilkUtilities.setToken(token); + synchronize(activity); + return null; + } catch (Exception e) { + // didn't work + exceptionService.reportError("rtm-verify-login", e); + rtmService = null; + if(e instanceof ServiceInternalException) + e = ((ServiceInternalException)e).getEnclosedException(); + return r.getString(R.string.rmilk_MLA_error, e.getMessage()); + } + } + }); + intent.putExtra(MilkLoginActivity.URL_TOKEN, url); + activity.startActivityForResult(intent, 0); + } else { + activity.startService(new Intent(MilkBackgroundService.SYNC_ACTION, null, + activity, MilkBackgroundService.class)); + } + } + // ---------------------------------------------------------------------- // ----------------------------------------------------- synchronization! // ---------------------------------------------------------------------- protected void performSync() { + FlurryAgent.onEvent("rtm-started"); //$NON-NLS-1$ + MilkUtilities.recordSyncStart(); + try { // get RTM timeline timeline = rtmService.timelines_create(); diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMTaskContainer.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMTaskContainer.java index 82e8cfaac..14d196cee 100644 --- a/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMTaskContainer.java +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMTaskContainer.java @@ -3,7 +3,7 @@ package com.todoroo.astrid.rmilk.sync; import java.util.ArrayList; import java.util.Iterator; -import com.todoroo.astrid.api.TaskContainer; +import com.todoroo.astrid.common.TaskContainer; import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Task; import com.todoroo.astrid.rmilk.api.data.RtmTaskSeries;