mirror of
https://github.com/etesync/android
synced 2024-12-23 15:18:14 +00:00
Handle errors when syncing journals, not just entries.
Also create a helper notification manager that encapsulates all of the notification creation logic (from throwable).
This commit is contained in:
parent
f2febfeb8c
commit
80bb0d6a70
@ -0,0 +1,84 @@
|
||||
package at.bitfire.davdroid;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.net.Uri;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.support.v7.app.NotificationCompat;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import at.bitfire.davdroid.journalmanager.Exceptions;
|
||||
import at.bitfire.davdroid.ui.AccountSettingsActivity;
|
||||
import at.bitfire.davdroid.ui.DebugInfoActivity;
|
||||
import at.bitfire.ical4android.CalendarStorageException;
|
||||
import at.bitfire.vcard4android.ContactsStorageException;
|
||||
import lombok.Getter;
|
||||
|
||||
public class NotificationHelper {
|
||||
final NotificationManagerCompat notificationManager;
|
||||
final Context context;
|
||||
final String notificationTag;
|
||||
final int notificationId;
|
||||
@Getter
|
||||
Intent detailsIntent;
|
||||
int messageString;
|
||||
|
||||
public NotificationHelper(Context context, String notificationTag, int notificationId) {
|
||||
this.notificationManager = NotificationManagerCompat.from(context);
|
||||
this.context = context;
|
||||
this.notificationTag = notificationTag;
|
||||
this.notificationId = notificationId;
|
||||
}
|
||||
|
||||
public void setThrowable(Throwable e) {
|
||||
if (e instanceof Exceptions.UnauthorizedException) {
|
||||
App.log.log(Level.SEVERE, "Not authorized anymore", e);
|
||||
messageString = R.string.sync_error_unauthorized;
|
||||
} else if (e instanceof Exceptions.ServiceUnavailableException) {
|
||||
App.log.log(Level.SEVERE, "Service unavailable");
|
||||
messageString = R.string.sync_error_unavailable;
|
||||
} else if (e instanceof Exceptions.HttpException) {
|
||||
App.log.log(Level.SEVERE, "HTTP Exception during sync", e);
|
||||
messageString = R.string.sync_error_http_dav;
|
||||
} else if (e instanceof CalendarStorageException || e instanceof ContactsStorageException || e instanceof SQLiteException) {
|
||||
App.log.log(Level.SEVERE, "Couldn't access local storage", e);
|
||||
messageString = R.string.sync_error_local_storage;
|
||||
} else if (e instanceof Exceptions.IntegrityException) {
|
||||
App.log.log(Level.SEVERE, "Integrity error", e);
|
||||
messageString = R.string.sync_error_integrity;
|
||||
} else {
|
||||
App.log.log(Level.SEVERE, "Unknown sync error", e);
|
||||
messageString = R.string.sync_error;
|
||||
}
|
||||
|
||||
if (e instanceof Exceptions.UnauthorizedException) {
|
||||
detailsIntent = new Intent(context, AccountSettingsActivity.class);
|
||||
} else {
|
||||
detailsIntent = new Intent(context, DebugInfoActivity.class);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_THROWABLE, e);
|
||||
}
|
||||
|
||||
detailsIntent.setData(Uri.parse("uri://" + getClass().getName() + "/" + notificationTag));
|
||||
}
|
||||
|
||||
public void notify(String title, String state) {
|
||||
String message = context.getString(messageString, state);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
|
||||
builder.setSmallIcon(R.drawable.ic_error_light)
|
||||
.setLargeIcon(App.getLauncherBitmap(context))
|
||||
.setContentTitle(title)
|
||||
.setContentIntent(PendingIntent.getActivity(context, 0, detailsIntent, PendingIntent.FLAG_CANCEL_CURRENT))
|
||||
.setCategory(NotificationCompat.CATEGORY_ERROR)
|
||||
.setContentText(message);
|
||||
|
||||
notificationManager.notify(notificationTag, notificationId, builder.build());
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
notificationManager.cancel(notificationTag, notificationId);
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ 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.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
@ -21,6 +22,7 @@ import android.database.sqlite.SQLiteException;
|
||||
import android.os.Bundle;
|
||||
import android.provider.CalendarContract;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@ -28,13 +30,17 @@ import java.util.logging.Level;
|
||||
|
||||
import at.bitfire.davdroid.AccountSettings;
|
||||
import at.bitfire.davdroid.App;
|
||||
import at.bitfire.davdroid.InvalidAccountException;
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.NotificationHelper;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.journalmanager.Exceptions;
|
||||
import at.bitfire.davdroid.model.CollectionInfo;
|
||||
import at.bitfire.davdroid.model.ServiceDB;
|
||||
import at.bitfire.davdroid.model.ServiceDB.Collections;
|
||||
import at.bitfire.davdroid.model.ServiceDB.Services;
|
||||
import at.bitfire.davdroid.resource.LocalCalendar;
|
||||
import at.bitfire.davdroid.ui.AccountSettingsActivity;
|
||||
import at.bitfire.davdroid.ui.DebugInfoActivity;
|
||||
import at.bitfire.ical4android.CalendarStorageException;
|
||||
import lombok.Cleanup;
|
||||
import okhttp3.HttpUrl;
|
||||
@ -57,6 +63,9 @@ public class CalendarsSyncAdapterService extends SyncAdapterService {
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||
super.onPerformSync(account, extras, authority, provider, syncResult);
|
||||
|
||||
NotificationHelper notificationManager = new NotificationHelper(getContext(), "journals", Constants.NOTIFICATION_CALENDAR_SYNC);
|
||||
notificationManager.cancel();
|
||||
|
||||
try {
|
||||
AccountSettings settings = new AccountSettings(getContext(), account);
|
||||
if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(settings))
|
||||
@ -71,15 +80,27 @@ public class CalendarsSyncAdapterService extends SyncAdapterService {
|
||||
CalendarSyncManager syncManager = new CalendarSyncManager(getContext(), account, settings, extras, authority, syncResult, calendar, principal);
|
||||
syncManager.performSync();
|
||||
}
|
||||
} catch (CalendarStorageException | SQLiteException e) {
|
||||
App.log.log(Level.SEVERE, "Couldn't prepare local calendars", e);
|
||||
syncResult.databaseError = true;
|
||||
} catch (InvalidAccountException e) {
|
||||
App.log.log(Level.SEVERE, "Couldn't get account settings", e);
|
||||
} catch (Exceptions.HttpException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exceptions.IntegrityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception | OutOfMemoryError e) {
|
||||
if (e instanceof CalendarStorageException || e instanceof SQLiteException) {
|
||||
App.log.log(Level.SEVERE, "Couldn't prepare local calendars", e);
|
||||
syncResult.databaseError = true;
|
||||
}
|
||||
|
||||
String syncPhase = SyncManager.SYNC_PHASE_JOURNALS;
|
||||
String title = getContext().getString(R.string.sync_error_calendar, account.name);
|
||||
|
||||
notificationManager.setThrowable(e);
|
||||
|
||||
final Intent detailsIntent = notificationManager.getDetailsIntent();
|
||||
if (e instanceof Exceptions.UnauthorizedException) {
|
||||
detailsIntent.putExtra(AccountSettingsActivity.EXTRA_ACCOUNT, account);
|
||||
} else {
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase);
|
||||
}
|
||||
|
||||
notificationManager.notify(title, syncPhase);
|
||||
}
|
||||
|
||||
App.log.info("Calendar sync complete");
|
||||
|
@ -13,6 +13,7 @@ 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.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
@ -20,16 +21,22 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import at.bitfire.davdroid.AccountSettings;
|
||||
import at.bitfire.davdroid.App;
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.InvalidAccountException;
|
||||
import at.bitfire.davdroid.NotificationHelper;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.journalmanager.Exceptions;
|
||||
import at.bitfire.davdroid.model.CollectionInfo;
|
||||
import at.bitfire.davdroid.model.ServiceDB;
|
||||
import at.bitfire.davdroid.model.ServiceDB.Collections;
|
||||
import at.bitfire.davdroid.ui.AccountSettingsActivity;
|
||||
import at.bitfire.davdroid.ui.DebugInfoActivity;
|
||||
import lombok.Cleanup;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
@ -50,6 +57,8 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
|
||||
@Override
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||
super.onPerformSync(account, extras, authority, provider, syncResult);
|
||||
NotificationHelper notificationManager = new NotificationHelper(getContext(), "journals", Constants.NOTIFICATION_CONTACTS_SYNC);
|
||||
notificationManager.cancel();
|
||||
|
||||
ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
|
||||
try {
|
||||
@ -72,12 +81,21 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
|
||||
}
|
||||
} else
|
||||
App.log.info("No CardDAV service found in DB");
|
||||
} catch (InvalidAccountException e) {
|
||||
App.log.log(Level.SEVERE, "Couldn't get account settings", e);
|
||||
} catch (Exceptions.HttpException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exceptions.IntegrityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception | OutOfMemoryError e) {
|
||||
String syncPhase = SyncManager.SYNC_PHASE_JOURNALS;
|
||||
String title = getContext().getString(R.string.sync_error_contacts, account.name);
|
||||
|
||||
notificationManager.setThrowable(e);
|
||||
|
||||
final Intent detailsIntent = notificationManager.getDetailsIntent();
|
||||
if (e instanceof Exceptions.UnauthorizedException) {
|
||||
detailsIntent.putExtra(AccountSettingsActivity.EXTRA_ACCOUNT, account);
|
||||
} else {
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase);
|
||||
}
|
||||
notificationManager.notify(title, syncPhase);
|
||||
} finally {
|
||||
dbHelper.close();
|
||||
}
|
||||
|
@ -9,14 +9,11 @@ package at.bitfire.davdroid.syncadapter;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SyncResult;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.support.v7.app.NotificationCompat;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@ -34,7 +31,7 @@ import at.bitfire.davdroid.App;
|
||||
import at.bitfire.davdroid.GsonHelper;
|
||||
import at.bitfire.davdroid.HttpClient;
|
||||
import at.bitfire.davdroid.InvalidAccountException;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.NotificationHelper;
|
||||
import at.bitfire.davdroid.journalmanager.Exceptions;
|
||||
import at.bitfire.davdroid.journalmanager.JournalEntryManager;
|
||||
import at.bitfire.davdroid.model.CollectionInfo;
|
||||
@ -50,7 +47,8 @@ import okhttp3.OkHttpClient;
|
||||
|
||||
abstract public class SyncManager {
|
||||
|
||||
protected final String SYNC_PHASE_PREPARE = "sync_phase_prepare",
|
||||
final static String SYNC_PHASE_PREPARE = "sync_phase_prepare",
|
||||
SYNC_PHASE_JOURNALS = "sync_phase_journals",
|
||||
SYNC_PHASE_QUERY_CAPABILITIES = "sync_phase_query_capabilities",
|
||||
SYNC_PHASE_PREPARE_LOCAL = "sync_phase_prepare_local",
|
||||
SYNC_PHASE_CREATE_LOCAL_ENTRIES = "sync_phase_create_local_entries",
|
||||
@ -62,7 +60,7 @@ abstract public class SyncManager {
|
||||
SYNC_PHASE_SAVE_SYNC_TAG = "sync_phase_save_sync_tag";
|
||||
|
||||
|
||||
protected final NotificationManagerCompat notificationManager;
|
||||
protected final NotificationHelper notificationManager;
|
||||
protected final String uniqueCollectionId;
|
||||
|
||||
protected final Context context;
|
||||
@ -113,8 +111,8 @@ abstract public class SyncManager {
|
||||
|
||||
// dismiss previous error notifications
|
||||
this.uniqueCollectionId = uniqueCollectionId;
|
||||
notificationManager = NotificationManagerCompat.from(context);
|
||||
notificationManager.cancel(uniqueCollectionId, notificationId());
|
||||
notificationManager = new NotificationHelper(context, uniqueCollectionId, notificationId());
|
||||
notificationManager.cancel();
|
||||
}
|
||||
|
||||
protected abstract int notificationId();
|
||||
@ -193,57 +191,30 @@ abstract public class SyncManager {
|
||||
// syncResult.delayUntil = (retryAfter.getTime() - new Date().getTime()) / 1000;
|
||||
}
|
||||
} catch (Exception | OutOfMemoryError e) {
|
||||
final int messageString;
|
||||
|
||||
if (e instanceof Exceptions.UnauthorizedException) {
|
||||
App.log.log(Level.SEVERE, "Not authorized anymore", e);
|
||||
messageString = R.string.sync_error_unauthorized;
|
||||
syncResult.stats.numAuthExceptions++;
|
||||
} else if (e instanceof Exceptions.HttpException) {
|
||||
App.log.log(Level.SEVERE, "HTTP Exception during sync", e);
|
||||
messageString = R.string.sync_error_http_dav;
|
||||
syncResult.stats.numParseExceptions++;
|
||||
} else if (e instanceof CalendarStorageException || e instanceof ContactsStorageException) {
|
||||
App.log.log(Level.SEVERE, "Couldn't access local storage", e);
|
||||
messageString = R.string.sync_error_local_storage;
|
||||
syncResult.databaseError = true;
|
||||
} else if (e instanceof Exceptions.IntegrityException) {
|
||||
App.log.log(Level.SEVERE, "Integrity error", e);
|
||||
messageString = R.string.sync_error_integrity;
|
||||
syncResult.stats.numParseExceptions++;
|
||||
} else {
|
||||
App.log.log(Level.SEVERE, "Unknown sync error", e);
|
||||
messageString = R.string.sync_error;
|
||||
syncResult.stats.numParseExceptions++;
|
||||
}
|
||||
|
||||
final Intent detailsIntent;
|
||||
notificationManager.setThrowable(e);
|
||||
|
||||
final Intent detailsIntent = notificationManager.getDetailsIntent();
|
||||
if (e instanceof Exceptions.UnauthorizedException) {
|
||||
detailsIntent = new Intent(context, AccountSettingsActivity.class);
|
||||
detailsIntent.putExtra(AccountSettingsActivity.EXTRA_ACCOUNT, account);
|
||||
} else {
|
||||
detailsIntent = new Intent(context, DebugInfoActivity.class);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_THROWABLE, e);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority);
|
||||
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase);
|
||||
}
|
||||
|
||||
// to make the PendingIntent unique
|
||||
detailsIntent.setData(Uri.parse("uri://" + getClass().getName() + "/" + uniqueCollectionId));
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
|
||||
builder.setSmallIcon(R.drawable.ic_error_light)
|
||||
.setLargeIcon(App.getLauncherBitmap(context))
|
||||
.setContentTitle(getSyncErrorTitle())
|
||||
.setContentIntent(PendingIntent.getActivity(context, 0, detailsIntent, PendingIntent.FLAG_CANCEL_CURRENT))
|
||||
.setCategory(NotificationCompat.CATEGORY_ERROR);
|
||||
|
||||
String message = context.getString(messageString, syncPhase);
|
||||
builder.setContentText(message);
|
||||
|
||||
|
||||
notificationManager.notify(uniqueCollectionId, notificationId(), builder.build());
|
||||
notificationManager.notify(getSyncErrorTitle(), syncPhase);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,6 +264,7 @@
|
||||
<string name="sync_error">Error while %s</string>
|
||||
<string name="sync_error_integrity">Integrity error while %s</string>
|
||||
<string name="sync_error_http_dav">Server error while %s</string>
|
||||
<string name="sync_error_unavailable">Could not connect to server while %s</string>
|
||||
<string name="sync_error_local_storage">Database error while %s</string>
|
||||
<string-array name="sync_error_phases">
|
||||
<item>preparing synchronization</item>
|
||||
|
Loading…
Reference in New Issue
Block a user