Display notification for recoverable auth errors

pull/467/head
Alex Baker 8 years ago
parent a8692ffd76
commit 904edd9b43

@ -17,7 +17,6 @@ import com.google.api.services.tasks.model.TaskLists;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import org.tasks.BuildConfig;
import org.tasks.analytics.Tracker;
import org.tasks.gtasks.GoogleTasksUnsuccessfulResponseHandler;
import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication;
@ -39,14 +38,12 @@ import timber.log.Timber;
public class GtasksInvoker {
private final Context context;
private final Tracker tracker;
private final GoogleAccountCredential credential;
private final Tasks service;
@Inject
public GtasksInvoker(@ForApplication Context context, GtasksPreferenceService preferenceService, Tracker tracker) {
public GtasksInvoker(@ForApplication Context context, GtasksPreferenceService preferenceService) {
this.context = context;
this.tracker = tracker;
credential = GoogleAccountCredential.usingOAuth2(context, Collections.singletonList(TasksScopes.TASKS));
setUserName(preferenceService.getUserName());
service = new Tasks.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
@ -124,16 +121,10 @@ public class GtasksInvoker {
private synchronized <T> T execute(TasksRequest<T> request) throws IOException {
String caller = getCaller();
Timber.d("%s request: %s", caller, request);
T response;
try {
HttpRequest httpRequest = request.buildHttpRequest();
httpRequest.setUnsuccessfulResponseHandler(new GoogleTasksUnsuccessfulResponseHandler(context, credential));
HttpResponse httpResponse = httpRequest.execute();
response = httpResponse.parseAs(request.getResponseClass());
} catch (IOException e) {
tracker.reportException(e);
throw e;
}
HttpRequest httpRequest = request.buildHttpRequest();
httpRequest.setUnsuccessfulResponseHandler(new GoogleTasksUnsuccessfulResponseHandler(context, credential));
HttpResponse httpResponse = httpRequest.execute();
T response = httpResponse.parseAs(request.getResponseClass());
Timber.d("%s response: %s", caller, prettyPrint(response));
return response;
}

@ -7,6 +7,7 @@ package com.todoroo.astrid.gtasks.sync;
import android.text.TextUtils;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Functions;
@ -24,6 +25,7 @@ import com.todoroo.astrid.gtasks.OrderedMetadataListUpdater;
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
import com.todoroo.astrid.gtasks.api.MoveRequest;
import org.tasks.analytics.Tracker;
import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.injection.ApplicationScope;
@ -46,17 +48,19 @@ public class GtasksSyncService {
private final GtasksInvoker gtasksInvoker;
private final LinkedBlockingQueue<SyncOnSaveOperation> operationQueue = new LinkedBlockingQueue<>();
private final SyncAdapterHelper syncAdapterHelper;
private final Tracker tracker;
@Inject
public GtasksSyncService(MetadataDao metadataDao, TaskDao taskDao,
GtasksPreferenceService gtasksPreferenceService,
GtasksInvoker gtasksInvoker,
SyncAdapterHelper syncAdapterHelper) {
SyncAdapterHelper syncAdapterHelper, Tracker tracker) {
this.metadataDao = metadataDao;
this.taskDao = taskDao;
this.gtasksPreferenceService = gtasksPreferenceService;
this.gtasksInvoker = gtasksInvoker;
this.syncAdapterHelper = syncAdapterHelper;
this.tracker = tracker;
new OperationPushThread(operationQueue).start();
}
@ -110,8 +114,10 @@ public class GtasksSyncService {
}
try {
op.op(gtasksInvoker);
} catch (UserRecoverableAuthIOException ignored) {
} catch (IOException e) {
Timber.e(e, e.getMessage());
tracker.reportException(e);
}
}
}

@ -17,14 +17,18 @@
package org.tasks.gtasks;
import android.accounts.Account;
import android.app.PendingIntent;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.services.tasks.model.TaskList;
import com.google.api.services.tasks.model.TaskLists;
import com.google.api.services.tasks.model.Tasks;
@ -50,12 +54,14 @@ import com.todoroo.astrid.gtasks.api.HttpNotFoundException;
import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
import com.todoroo.astrid.gtasks.sync.GtasksTaskContainer;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Constants;
import org.tasks.Broadcaster;
import org.tasks.R;
import org.tasks.analytics.Tracker;
import org.tasks.injection.InjectingAbstractThreadedSyncAdapter;
import org.tasks.injection.SyncAdapterComponent;
import org.tasks.notifications.NotificationManager;
import org.tasks.preferences.Preferences;
import org.tasks.sync.RecordSyncStatusCallback;
import org.tasks.time.DateTime;
@ -98,6 +104,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
@Inject MetadataDao metadataDao;
@Inject GtasksMetadata gtasksMetadataFactory;
@Inject Tracker tracker;
@Inject NotificationManager notificationManager;
public GoogleTaskSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
@ -135,6 +142,11 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
callback.started();
synchronize();
gtasksPreferenceService.recordSuccessfulSync();
} catch (UserRecoverableAuthIOException e) {
Timber.e(e, e.getMessage());
sendNotification(getContext(), e.getIntent());
} catch (IOException e) {
Timber.e(e, e.getMessage());
} catch (Exception e) {
tracker.reportException(e);
} finally {
@ -143,6 +155,20 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
}
}
private void sendNotification(Context context, Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_FROM_BACKGROUND);
PendingIntent resolve = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setAutoCancel(true)
.setContentIntent(resolve)
.setContentTitle(context.getString(R.string.sync_error_permissions))
.setContentText(context.getString(R.string.common_google_play_services_notification_ticker))
.setAutoCancel(true)
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.setTicker(context.getString(R.string.common_google_play_services_notification_ticker));
notificationManager.notify(Constants.NOTIFICATION_SYNC_ERROR, builder.build());
}
private void synchronize() throws IOException {
pushLocalChanges();
@ -168,13 +194,15 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
}
}
private void pushLocalChanges() {
private void pushLocalChanges() throws UserRecoverableAuthIOException {
List<Task> tasks = taskDao.toList(Query.select(Task.PROPERTIES)
.join(Join.left(Metadata.TABLE, Criterion.and(MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY), Task.ID.eq(Metadata.TASK))))
.where(Criterion.or(Task.MODIFICATION_DATE.gt(GtasksMetadata.LAST_SYNC), GtasksMetadata.ID.eq(""))));
for (Task task : tasks) {
try {
pushTask(task, task.getMergedValues(), gtasksInvoker);
} catch (UserRecoverableAuthIOException e) {
throw e;
} catch (IOException e) {
tracker.reportException(e);
}
@ -292,7 +320,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
MetadataDao.MetadataCriteria.isDeleted()));
}
private synchronized void fetchAndApplyRemoteChanges(GtasksList list) {
private synchronized void fetchAndApplyRemoteChanges(GtasksList list) throws UserRecoverableAuthIOException {
String listId = list.getRemoteId();
long lastSyncDate = list.getLastSync();
@ -327,6 +355,8 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
storeObjectDao.persist(list);
gtasksTaskListUpdater.correctOrderAndIndentForList(listId);
}
} catch (UserRecoverableAuthIOException e) {
throw e;
} catch (IOException e) {
tracker.reportException(e);
}

@ -42,7 +42,10 @@ public class GoogleTasksUnsuccessfulResponseHandler implements HttpUnsuccessfulR
}
int statusCode = response.getStatusCode();
if ((statusCode == HttpStatusCodes.STATUS_CODE_UNAUTHORIZED || statusCode == HttpStatusCodes.STATUS_CODE_FORBIDDEN)) {
clearToken(googleAccountCredential);
boolean shouldRetry = clearToken(googleAccountCredential);
if (!shouldRetry) {
return false;
}
} else if (statusCode == 400) { // bad request
throw httpResponseException;
} else if (statusCode == HttpStatusCodes.STATUS_CODE_NOT_FOUND) {
@ -52,15 +55,19 @@ public class GoogleTasksUnsuccessfulResponseHandler implements HttpUnsuccessfulR
return backoffHandler.handleResponse(request, response, supportsRetry);
}
private void clearToken(GoogleAccountCredential credential) throws IOException {
private boolean clearToken(GoogleAccountCredential credential){
try {
String token = credential.getToken();
Timber.d("Invalidating %s", token);
GoogleAuthUtil.clearToken(context, token);
GoogleAuthUtil.getTokenWithNotification(context, credential.getSelectedAccount(), "oauth2:" + TasksScopes.TASKS, null);
GoogleAuthUtil.getToken(context, credential.getSelectedAccount(), "oauth2:" + TasksScopes.TASKS, null);
return true;
} catch (GoogleAuthException e) {
Timber.e(e, e.getMessage());
throw new IOException(e);
return false;
} catch (IOException e) {
Timber.e(e, e.getMessage());
return true;
}
}
}

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

@ -18,4 +18,5 @@ public final class Constants {
/** Notification Manager id for timing */
public static final int NOTIFICATION_TIMER = -2;
public static final int NOTIFICATION_SYNC_ERROR = -3;
}

@ -822,5 +822,6 @@ File %1$s contained %2$s.\n\n
<string name="widget_row_settings">Row settings</string>
<string name="notification_shade">Notification shade</string>
<string name="notification_description">Show task description</string>
<string name="sync_error_permissions">Tasks requires permission</string>
</resources>

Loading…
Cancel
Save