Adding better error reporting facilities via flurry, plus a few more flurry events.

pull/14/head
Tim Su 17 years ago
parent 349e50c6c4
commit eae64b19e9

@ -90,7 +90,7 @@ public class Invoker {
public static final String API_SIG_PARAM = "api_sig"; public static final String API_SIG_PARAM = "api_sig";
public static final long INVOCATION_INTERVAL = 300; public static final long INVOCATION_INTERVAL = 400;
private long lastInvocation; private long lastInvocation;
@ -108,248 +108,209 @@ public class Invoker {
private HttpClient httpClient; private HttpClient httpClient;
public Invoker(String serverHostName, int serverPortNumber, String serviceRelativeUri, ApplicationInfo applicationInfo) public Invoker(String serverHostName, int serverPortNumber,
throws ServiceInternalException String serviceRelativeUri, ApplicationInfo applicationInfo)
{ throws ServiceInternalException {
this.serviceRelativeUri = serviceRelativeUri;
new HttpHost(serverHostName, serverPortNumber); this.serviceRelativeUri = serviceRelativeUri;
globalHttpParams = new BasicHttpParams(); new HttpHost(serverHostName, serverPortNumber);
HttpProtocolParams.setVersion(globalHttpParams, HttpVersion.HTTP_1_1); globalHttpParams = new BasicHttpParams();
HttpProtocolParams.setContentCharset(globalHttpParams, ENCODING); HttpProtocolParams.setVersion(globalHttpParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setUseExpectContinue(globalHttpParams, true); HttpProtocolParams.setContentCharset(globalHttpParams, ENCODING);
HttpProtocolParams.setUseExpectContinue(globalHttpParams, true);
basicHeader = new BasicHeader(HTTP.CHARSET_PARAM, ENCODING);
basicHeader = new BasicHeader(HTTP.CHARSET_PARAM, ENCODING);
httpProcessor = new BasicHttpProcessor();
// Required protocol interceptors httpProcessor = new BasicHttpProcessor();
httpProcessor.addInterceptor(new RequestContent()); // Required protocol interceptors
httpProcessor.addInterceptor(new RequestTargetHost()); httpProcessor.addInterceptor(new RequestContent());
// Recommended protocol interceptors httpProcessor.addInterceptor(new RequestTargetHost());
httpProcessor.addInterceptor(new RequestConnControl()); // Recommended protocol interceptors
httpProcessor.addInterceptor(new RequestUserAgent()); httpProcessor.addInterceptor(new RequestConnControl());
httpProcessor.addInterceptor(new RequestExpectContinue()); httpProcessor.addInterceptor(new RequestUserAgent());
httpProcessor.addInterceptor(new RequestExpectContinue());
httpClient = new DefaultHttpClient();
httpClient = new DefaultHttpClient();
lastInvocation = System.currentTimeMillis();
this.applicationInfo = applicationInfo; lastInvocation = System.currentTimeMillis();
this.applicationInfo = applicationInfo;
try
{ try {
digest = MessageDigest.getInstance("md5"); digest = MessageDigest.getInstance("md5");
} } catch (NoSuchAlgorithmException e) {
catch (NoSuchAlgorithmException e) throw new ServiceInternalException(
{ "Could not create properly the MD5 digest", e);
throw new ServiceInternalException("Could not create properly the MD5 digest", e); }
} }
}
private StringBuffer computeRequestUri(Param... params) private StringBuffer computeRequestUri(Param... params)
throws ServiceInternalException throws ServiceInternalException {
{ final StringBuffer requestUri = new StringBuffer(serviceRelativeUri);
final StringBuffer requestUri = new StringBuffer(serviceRelativeUri); if (params.length > 0) {
if (params.length > 0) requestUri.append("?");
{ }
requestUri.append("?"); for (Param param : params) {
} try {
for (Param param : params) requestUri.append(param.getName()).append("=").append(
{ URLEncoder.encode(param.getValue(), ENCODING)).append(
try "&");
{ } catch (Exception exception) {
requestUri.append(param.getName()).append("=").append(URLEncoder.encode(param.getValue(), ENCODING)).append("&"); final StringBuffer message = new StringBuffer(
} "Cannot encode properly the HTTP GET request URI: cannot execute query");
catch (Exception exception) Log.e(TAG, message.toString(), exception);
{ throw new ServiceInternalException(message.toString());
final StringBuffer message = new StringBuffer("Cannot encode properly the HTTP GET request URI: cannot execute query"); }
Log.e(TAG, message.toString(), exception); }
throw new ServiceInternalException(message.toString()); requestUri.append(API_SIG_PARAM).append("=").append(calcApiSig(params));
} return requestUri;
} }
requestUri.append(API_SIG_PARAM).append("=").append(calcApiSig(params));
return requestUri;
}
/** Call invoke with a false repeat */ /** Call invoke with a false repeat */
public Element invoke(Param... params) throws ServiceException { public Element invoke(Param... params) throws ServiceException {
return invoke(false, params); return invoke(false, params);
}
public Element invoke(boolean repeat, Param... params)
throws ServiceException
{
long timeSinceLastInvocation = System.currentTimeMillis() - lastInvocation;
if (timeSinceLastInvocation < INVOCATION_INTERVAL)
{
// In order not to invoke the RTM service too often
try
{
Thread.sleep(INVOCATION_INTERVAL - timeSinceLastInvocation);
}
catch (InterruptedException e)
{
throw new ServiceInternalException("Unexpected interruption while attempting to pause for some time before invoking the RTM service back", e);
}
} }
// We prepare the network socket-based connection public Element invoke(boolean repeat, Param... params)
//prepareConnection(); throws ServiceException {
long timeSinceLastInvocation = System.currentTimeMillis() -
// We compute the URI lastInvocation;
final StringBuffer requestUri = computeRequestUri(params); if (timeSinceLastInvocation < INVOCATION_INTERVAL) {
HttpResponse response = null; // In order not to invoke the RTM service too often
final HttpGet request = new HttpGet("http://" + ServiceImpl.SERVER_HOST_NAME + requestUri.toString());
request.setHeader(basicHeader);
final String methodUri = request.getRequestLine().getUri();
Element result;
try
{
Log.i(TAG, "Executing the method:" + methodUri);
response = httpClient.execute(request);
// httpExecutor.execute(request, connection, context);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK)
{
Log.e(TAG, "Method failed: " + response.getStatusLine());
// Tim: HTTP error. Let's wait a little bit
if(!repeat) {
try { try {
Thread.sleep(1500); Thread.sleep(INVOCATION_INTERVAL - timeSinceLastInvocation);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// ignore return null;
} }
return invoke(true, params);
} }
throw new ServiceInternalException("method failed: " + response.getStatusLine()); // We compute the URI
} final StringBuffer requestUri = computeRequestUri(params);
HttpResponse response = null;
// THINK: this method is deprecated, but the only way to get the body as a string, without consuming
// the body input stream: the HttpMethodBase issues a warning but does not let you call the "setResponseStream()" method! final HttpGet request = new HttpGet("http://"
final String responseBodyAsString = "";//EntityUtils.toString(response.getEntity()); + ServiceImpl.SERVER_HOST_NAME + requestUri.toString());
// Log.i(TAG, " Invocation response:\r\n" + responseBodyAsString); request.setHeader(basicHeader);
final Document responseDoc = builder.parse(response.getEntity().getContent()); final String methodUri = request.getRequestLine().getUri();
final Element wrapperElt = responseDoc.getDocumentElement();
if (!wrapperElt.getNodeName().equals("rsp")) Element result;
{ try {
throw new ServiceInternalException("unexpected response returned by RTM service: " + responseBodyAsString); Log.i(TAG, "Executing the method:" + methodUri);
} response = httpClient.execute(request);
else
{ final int statusCode = response.getStatusLine().getStatusCode();
String stat = wrapperElt.getAttribute("stat"); if (statusCode != HttpStatus.SC_OK) {
if (stat.equals("fail")) Log.e(TAG, "Method failed: " + response.getStatusLine());
{
Node errElt = wrapperElt.getFirstChild(); // Tim: HTTP error. Let's wait a little bit
while (errElt != null && (errElt.getNodeType() != Node.ELEMENT_NODE || !errElt.getNodeName().equals("err"))) if (!repeat) {
{ try {
errElt = errElt.getNextSibling(); Thread.sleep(1500);
} } catch (InterruptedException e) {
if (errElt == null) // ignore
{ }
throw new ServiceInternalException("unexpected response returned by RTM service: " + responseBodyAsString); return invoke(true, params);
} }
else
{ throw new ServiceInternalException("method failed: "
throw new ServiceException(Integer.parseInt(((Element) errElt).getAttribute("code")), ((Element) errElt).getAttribute("msg")); + response.getStatusLine());
}
}
else
{
Node dataElt = wrapperElt.getFirstChild();
while (dataElt != null && (dataElt.getNodeType() != Node.ELEMENT_NODE || dataElt.getNodeName().equals("transaction") == true))
{
try
{
Node nextSibling = dataElt.getNextSibling();
if (nextSibling == null)
{
break;
}
else
{
dataElt = nextSibling;
}
} }
catch (IndexOutOfBoundsException exception)
{ final Document responseDoc = builder.parse(response.getEntity()
// Some implementation may throw this exception, instead of returning a null sibling .getContent());
break; final Element wrapperElt = responseDoc.getDocumentElement();
if (!wrapperElt.getNodeName().equals("rsp")) {
throw new ServiceInternalException(
"unexpected response returned by RTM service: "
+ wrapperElt.getNodeName());
} else {
String stat = wrapperElt.getAttribute("stat");
if (stat.equals("fail")) {
Node errElt = wrapperElt.getFirstChild();
while (errElt != null
&& (errElt.getNodeType() != Node.ELEMENT_NODE || !errElt
.getNodeName().equals("err"))) {
errElt = errElt.getNextSibling();
}
if (errElt == null) {
throw new ServiceInternalException(
"unexpected response returned by RTM service: "
+ wrapperElt.getNodeValue());
} else {
throw new ServiceException(Integer
.parseInt(((Element) errElt)
.getAttribute("code")),
((Element) errElt).getAttribute("msg"));
}
} else {
Node dataElt = wrapperElt.getFirstChild();
while (dataElt != null
&& (dataElt.getNodeType() != Node.ELEMENT_NODE || dataElt
.getNodeName().equals("transaction") == true)) {
try {
Node nextSibling = dataElt.getNextSibling();
if (nextSibling == null) {
break;
} else {
dataElt = nextSibling;
}
} catch (IndexOutOfBoundsException exception) {
// Some implementation may throw this exception,
// instead of returning a null sibling
break;
}
}
if (dataElt == null) {
throw new ServiceInternalException(
"unexpected response returned by RTM service: "
+ wrapperElt.getNodeValue());
} else {
result = (Element) dataElt;
}
}
} }
} } catch (IOException e) {
if (dataElt == null) throw new ServiceInternalException("Connection error", e);
{ } catch (SAXException e) {
throw new ServiceInternalException("unexpected response returned by RTM service: " + responseBodyAsString); throw new ServiceInternalException("XML Parse Exception", e);
} } finally {
else httpClient.getConnectionManager().closeExpiredConnections();
{
result = (Element) dataElt;
}
} }
}
}
catch (IOException e)
{
throw new ServiceInternalException("Connection error", e);
}
catch (SAXException e)
{
throw new ServiceInternalException("XML Parse Exception", e);
}
// catch (HttpException e)
// {
// throw new ServiceInternalException("", e);
// }
finally
{
httpClient.getConnectionManager().closeExpiredConnections();
}
lastInvocation = System.currentTimeMillis(); lastInvocation = System.currentTimeMillis();
return result; return result;
}
final String calcApiSig(Param... params)
throws ServiceInternalException
{
try
{
digest.reset();
digest.update(applicationInfo.getSharedSecret().getBytes(ENCODING));
List<Param> sorted = Arrays.asList(params);
Collections.sort(sorted);
for (Param param : sorted)
{
digest.update(param.getName().getBytes(ENCODING));
digest.update(param.getValue().getBytes(ENCODING));
}
return convertToHex(digest.digest());
} }
catch (UnsupportedEncodingException e)
{ final String calcApiSig(Param... params) throws ServiceInternalException {
throw new ServiceInternalException("cannot hahdle properly the encoding", e); try {
digest.reset();
digest.update(applicationInfo.getSharedSecret().getBytes(ENCODING));
List<Param> sorted = Arrays.asList(params);
Collections.sort(sorted);
for (Param param : sorted) {
digest.update(param.getName().getBytes(ENCODING));
digest.update(param.getValue().getBytes(ENCODING));
}
return convertToHex(digest.digest());
} catch (UnsupportedEncodingException e) {
throw new ServiceInternalException(
"cannot hahdle properly the encoding", e);
}
} }
}
private static String convertToHex(byte[] data) private static String convertToHex(byte[] data) {
{ StringBuffer buf = new StringBuffer();
StringBuffer buf = new StringBuffer(); for (int i = 0; i < data.length; i++) {
for (int i = 0; i < data.length; i++) int halfbyte = (data[i] >>> 4) & 0x0F;
{ int two_halfs = 0;
int halfbyte = (data[i] >>> 4) & 0x0F; do {
int two_halfs = 0; if ((0 <= halfbyte) && (halfbyte <= 9))
do buf.append((char) ('0' + halfbyte));
{ else
if ((0 <= halfbyte) && (halfbyte <= 9)) buf.append((char) ('a' + (halfbyte - 10)));
buf.append((char) ('0' + halfbyte)); halfbyte = data[i] & 0x0F;
else } while (two_halfs++ < 1);
buf.append((char) ('a' + (halfbyte - 10))); }
halfbyte = data[i] & 0x0F; return buf.toString();
}
while (two_halfs++ < 1);
} }
return buf.toString();
}
} }

@ -55,6 +55,7 @@ import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.timsu.astrid.data.tag.TagIdentifier; import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.tag.TagModelForView; import com.timsu.astrid.data.tag.TagModelForView;
@ -104,6 +105,8 @@ public class TagListSubActivity extends SubActivity {
fillData(); fillData();
} }
}).start(); }).start();
FlurryAgent.onEvent("view-tags");
} }
// --- stuff for sorting // --- stuff for sorting

File diff suppressed because it is too large Load Diff

@ -56,6 +56,7 @@ import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagModelForView; import com.timsu.astrid.data.tag.TagModelForView;
import com.timsu.astrid.data.task.AbstractTaskModel; import com.timsu.astrid.data.task.AbstractTaskModel;
import com.timsu.astrid.data.task.TaskModelForSync; import com.timsu.astrid.data.task.TaskModelForSync;
import com.timsu.astrid.utilities.AstridUtilities;
import com.timsu.astrid.utilities.DialogUtilities; import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Preferences; import com.timsu.astrid.utilities.Preferences;
@ -153,8 +154,8 @@ public class RTMSyncProvider extends SynchronizationProvider {
return true; return true;
} catch (final Exception e) { } catch (final Exception e) {
// didn't work // didn't work
FlurryAgent.onError("rtm-error-verify-login", e.toString(), FlurryAgent.onError("rtm-verify-login", AstridUtilities.throwableToString(e),
e.getClass().getSimpleName()); SynchronizationProvider.class.getSimpleName());
syncLoginHandler.post(new Runnable() { syncLoginHandler.post(new Runnable() {
@Override @Override
@ -178,8 +179,8 @@ public class RTMSyncProvider extends SynchronizationProvider {
} }
} catch (Exception e) { } catch (Exception e) {
FlurryAgent.onError("rtm-error-authenticate", e.toString(), FlurryAgent.onError("rtm-authenticate", AstridUtilities.throwableToString(e),
e.getClass().getSimpleName()); SynchronizationProvider.class.getSimpleName());
// IO Exception // IO Exception
if(e instanceof ServiceInternalException && if(e instanceof ServiceInternalException &&
@ -258,8 +259,8 @@ public class RTMSyncProvider extends SynchronizationProvider {
postUpdate(new ProgressUpdater(5, 5)); postUpdate(new ProgressUpdater(5, 5));
addTasksToList(context, tasks, remoteChanges); addTasksToList(context, tasks, remoteChanges);
} catch (Exception e) { } catch (Exception e) {
FlurryAgent.onError("rtm-error-quick-sync", e.toString(), FlurryAgent.onError("rtm-quick-sync", AstridUtilities.throwableToString(e),
e.getClass().getSimpleName()); SynchronizationProvider.class.getSimpleName());
Log.e("rtmsync", "Error sync-ing list!", e); Log.e("rtmsync", "Error sync-ing list!", e);
remoteChanges.clear(); remoteChanges.clear();
@ -279,8 +280,8 @@ public class RTMSyncProvider extends SynchronizationProvider {
filter, lastSyncDate); filter, lastSyncDate);
addTasksToList(context, tasks, remoteChanges); addTasksToList(context, tasks, remoteChanges);
} catch (Exception e) { } catch (Exception e) {
FlurryAgent.onError("rtm-error-indiv-sync", e.toString(), FlurryAgent.onError("rtm-indiv-sync", AstridUtilities.throwableToString(e),
e.getClass().getSimpleName()); SynchronizationProvider.class.getSimpleName());
Log.e("rtmsync", "Error sync-ing list!", e); Log.e("rtmsync", "Error sync-ing list!", e);
postUpdate(new Runnable() { postUpdate(new Runnable() {
@ -305,8 +306,8 @@ public class RTMSyncProvider extends SynchronizationProvider {
FlurryAgent.onEvent("rtm-sync-finished"); FlurryAgent.onEvent("rtm-sync-finished");
} catch (Exception e) { } catch (Exception e) {
FlurryAgent.onError("rtm-error-sync", e.toString(), FlurryAgent.onError("rtm-sync", AstridUtilities.throwableToString(e),
e.getClass().getSimpleName()); SynchronizationProvider.class.getSimpleName());
Log.e("rtmsync", "Error in synchronization", e); Log.e("rtmsync", "Error in synchronization", e);
showError(context, e, null); showError(context, e, null);

@ -43,6 +43,7 @@ import com.timsu.astrid.data.task.AbstractTaskModel;
import com.timsu.astrid.data.task.TaskController; import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier; import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForSync; import com.timsu.astrid.data.task.TaskModelForSync;
import com.timsu.astrid.utilities.AstridUtilities;
import com.timsu.astrid.utilities.DialogUtilities; import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Notifications; import com.timsu.astrid.utilities.Notifications;
import com.timsu.astrid.utilities.Preferences; import com.timsu.astrid.utilities.Preferences;
@ -63,8 +64,7 @@ public abstract class SynchronizationProvider {
this.id = id; this.id = id;
} }
/** Called off the UI thread. does some setup and then invokes implemented /** Does some setup and then invokes implemented synchronize method
* synchronize method
* @param activity * @param activity
* @param caller * @param caller
*/ */
@ -72,16 +72,21 @@ public abstract class SynchronizationProvider {
this.synchronizer = caller; this.synchronizer = caller;
if(!isBackgroundService()) { if(!isBackgroundService()) {
syncHandler = new Handler(); syncHandler = caller.getHandler();
SynchronizationProvider.progressDialog = new ProgressDialog(activity); syncHandler.post(new Runnable() {
progressDialog.setIcon(android.R.drawable.ic_dialog_alert); @Override
progressDialog.setTitle("Synchronization"); public void run() {
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); SynchronizationProvider.progressDialog = new ProgressDialog(activity);
progressDialog.setMax(100); progressDialog.setIcon(android.R.drawable.ic_dialog_alert);
progressDialog.setMessage("Checking Authorization..."); progressDialog.setTitle("Synchronization");
progressDialog.setProgress(0); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(false); progressDialog.setMax(100);
progressDialog.show(); progressDialog.setMessage("Checking Authorization...");
progressDialog.setProgress(0);
progressDialog.setCancelable(false);
progressDialog.show();
}
});
} }
synchronize(activity); synchronize(activity);
@ -121,6 +126,8 @@ public abstract class SynchronizationProvider {
*/ */
void showError(final Context context, Throwable e, String message) { void showError(final Context context, Throwable e, String message) {
Log.e("astrid", "Synchronization Error", e); Log.e("astrid", "Synchronization Error", e);
FlurryAgent.onError("sync-error", AstridUtilities.throwableToString(e),
SynchronizationProvider.class.getSimpleName());
if(isBackgroundService()) if(isBackgroundService())
return; return;
@ -146,7 +153,7 @@ public abstract class SynchronizationProvider {
* to console if we're a background sync. * to console if we're a background sync.
*/ */
protected void postUpdate(Runnable updater) { protected void postUpdate(Runnable updater) {
if(isBackgroundService()) { if(isBackgroundService() || syncHandler == null) {
// only run jobs if they can actually be processed // only run jobs if they can actually be processed
if(updater instanceof ProgressLabelUpdater) if(updater instanceof ProgressLabelUpdater)
updater.run(); updater.run();
@ -301,8 +308,8 @@ public abstract class SynchronizationProvider {
else else
log.append("updated '" + task.getName() + "'\n"); log.append("updated '" + task.getName() + "'\n");
} catch (Exception e) { } catch (Exception e) {
FlurryAgent.onError("sync-error-push-task", e.toString(), FlurryAgent.onError("sync-push-task", AstridUtilities.throwableToString(e),
e.getClass().getSimpleName()); SynchronizationProvider.class.getSimpleName());
Log.e("astrid", "Exception pushing task", e); Log.e("astrid", "Exception pushing task", e);
log.append("error sending '" + task.getName() + "'\n"); log.append("error sending '" + task.getName() + "'\n");

@ -106,6 +106,7 @@ public class SynchronizationService extends Service {
performSynchronization(); performSynchronization();
} }
}, offset, interval); }, offset, interval);
Log.i("astrid", "Synchronization Service Started, Offset: " + offset/1000 + Log.i("astrid", "Synchronization Service Started, Offset: " + offset/1000 +
"s Interval: " + interval/1000); "s Interval: " + interval/1000);
} }

@ -24,6 +24,8 @@ import java.util.Date;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import com.timsu.astrid.activities.TaskListSubActivity; import com.timsu.astrid.activities.TaskListSubActivity;
@ -47,15 +49,15 @@ import com.timsu.astrid.utilities.Preferences;
*/ */
public class Synchronizer { public class Synchronizer {
/** identifier for the RTM sync provider */ /** identifier for the RTM sync provider */
private static final int SYNC_ID_RTM = 1; private static final int SYNC_ID_RTM = 1;
// --- public interface // --- public interface
/** Synchronize all tasks */ /** Synchronize all tasks */
public Synchronizer(boolean isService) { public Synchronizer(boolean isService) {
this.isService = isService; this.isService = isService;
singleTaskForSync = null; singleTaskForSync = null;
} }
/** Synchronize a specific task only */ /** Synchronize a specific task only */
@ -68,15 +70,19 @@ public class Synchronizer {
void onSynchronizerFinished(int numServicesSynced); void onSynchronizerFinished(int numServicesSynced);
} }
/** Synchronize all activated sync services */ /** Synchronize all activated sync services. */
public synchronized void synchronize(Context context, SynchronizerListener listener) { public synchronized void synchronize(Context context,
SynchronizerListener listener) {
currentStep = ServiceWrapper._FIRST_SERVICE.ordinal(); currentStep = ServiceWrapper._FIRST_SERVICE.ordinal();
servicesSynced = 0; servicesSynced = 0;
callback = listener; callback = listener;
// if we're not the autosync service, stop it // if we're not the autosync service, stop it. also create handler
if(!isService) if(!isService) {
SynchronizationService.stop(); SynchronizationService.stop();
if(Looper.myLooper() != null)
handler = new Handler();
}
continueSynchronization(context); continueSynchronization(context);
} }
@ -134,6 +140,9 @@ public class Synchronizer {
// Internal state for the synchronization process // Internal state for the synchronization process
/** Handler for sending jobs to the UI thread */
private Handler handler = null;
/** Current step in the sync process */ /** Current step in the sync process */
private int currentStep = 0; private int currentStep = 0;
@ -150,13 +159,17 @@ public class Synchronizer {
private final TaskIdentifier singleTaskForSync; private final TaskIdentifier singleTaskForSync;
boolean isService() { boolean isService() {
return isService; return isService;
} }
TaskIdentifier getSingleTaskForSync() { TaskIdentifier getSingleTaskForSync() {
return singleTaskForSync; return singleTaskForSync;
} }
Handler getHandler() {
return handler;
}
/** Called to do the next step of synchronization. */ /** Called to do the next step of synchronization. */
void continueSynchronization(Context context) { void continueSynchronization(Context context) {
ServiceWrapper serviceWrapper = ServiceWrapper serviceWrapper =
@ -185,12 +198,14 @@ public class Synchronizer {
if(callback != null) if(callback != null)
callback.onSynchronizerFinished(servicesSynced); callback.onSynchronizerFinished(servicesSynced);
if(getSingleTaskForSync() != null) if(getSingleTaskForSync() == null)
Preferences.setSyncLastSync(context, new Date()); Preferences.setSyncLastSync(context, new Date());
if(!isService) { if(!isService) {
SynchronizationService.start(); SynchronizationService.start();
TaskListSubActivity.shouldRefreshTaskList = true; TaskListSubActivity.shouldRefreshTaskList = true;
} }
Log.i("sync", "Synchronization Service Finished");
} }
// --- controller stuff // --- controller stuff
@ -236,8 +251,8 @@ public class Synchronizer {
} }
public void set(TYPE newController) { public void set(TYPE newController) {
if(controller != null && !override) if(controller != null && !override)
close(); close();
override = newController != null; override = newController != null;
controller = newController; controller = newController;

@ -0,0 +1,30 @@
package com.timsu.astrid.utilities;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* General purpose utilities for the Astrid project. Grab-bag of stuff.
*
* @author timsu
*
*/
public class AstridUtilities {
/**
* Converts a throwable's stack trace into a string
*
* @param input
* @return
*/
public static String throwableToString(Throwable input) {
StringWriter writer = new StringWriter();
PrintWriter writerPrinter = new PrintWriter(writer);
input.printStackTrace(writerPrinter);
writerPrinter.flush();
writerPrinter.close();
return writer.toString();
}
}
Loading…
Cancel
Save