diff --git a/app/src/main/java/com/etesync/syncadapter/NotificationHelper.java b/app/src/main/java/com/etesync/syncadapter/NotificationHelper.java index 3c708a5c..327df9b8 100644 --- a/app/src/main/java/com/etesync/syncadapter/NotificationHelper.java +++ b/app/src/main/java/com/etesync/syncadapter/NotificationHelper.java @@ -30,6 +30,8 @@ public class NotificationHelper { Intent detailsIntent; int messageString; + private Throwable throwable = null; + public NotificationHelper(Context context, String notificationTag, int notificationId) { this.notificationManager = NotificationManagerCompat.from(context); this.context = context; @@ -38,6 +40,7 @@ public class NotificationHelper { } public void setThrowable(Throwable e) { + throwable = e; if (e instanceof Exceptions.UnauthorizedException) { App.log.log(Level.SEVERE, "Not authorized anymore", e); messageString = R.string.sync_error_unauthorized; @@ -68,18 +71,39 @@ public class NotificationHelper { public void notify(String title, String state) { String message = context.getString(messageString, state); + notify(title, message, null, detailsIntent); + } + public void notify(String title, String content, String bigText, Intent intent) { NotificationCompat.Builder builder = new NotificationCompat.Builder(context); - builder.setSmallIcon(R.drawable.ic_error_light) - .setLargeIcon(App.getLauncherBitmap(context)) + int icon; + String category; + String tag; + //Check if error was configured + if (throwable == null) { + icon = R.drawable.ic_sync_dark; + category = NotificationCompat.CATEGORY_STATUS; + } else { + icon = R.drawable.ic_error_light; + category = NotificationCompat.CATEGORY_ERROR; + } + + builder.setLargeIcon(App.getLauncherBitmap(context)) .setContentTitle(title) - .setContentIntent(PendingIntent.getActivity(context, 0, detailsIntent, PendingIntent.FLAG_CANCEL_CURRENT)) - .setCategory(NotificationCompat.CATEGORY_ERROR) - .setContentText(message); + .setContentText(content) + .setAutoCancel(true) + .setCategory(category) + .setSmallIcon(icon) + .setContentIntent(PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)) + ; + + if (bigText != null) builder.setStyle(new NotificationCompat.BigTextStyle() + .bigText(bigText)); notificationManager.notify(notificationTag, notificationId, builder.build()); } + public void cancel() { notificationManager.cancel(notificationTag, notificationId); } diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java index 9b3c4183..a793c022 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java @@ -59,6 +59,12 @@ public class CalendarSyncManager extends SyncManager { return context.getString(R.string.sync_error_calendar, account.name); } + @Override + protected String getSyncSuccessfullyTitle() { + return context.getString(R.string.sync_successfully_calendar, info.displayName, + account.name); + } + @Override protected boolean prepare() throws ContactsStorageException, CalendarStorageException { if (!super.prepare()) diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java index e49c36cf..392a9961 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java @@ -82,6 +82,11 @@ public class ContactsSyncManager extends SyncManager { return context.getString(R.string.sync_error_contacts, account.name); } + @Override + protected String getSyncSuccessfullyTitle() { + return context.getString(R.string.sync_successfully_contacts, account.name); + } + @Override protected boolean prepare() throws ContactsStorageException, CalendarStorageException { if (!super.prepare()) diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java index e9042699..9803fa96 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java @@ -12,6 +12,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.SyncResult; +import android.content.res.Resources; import android.os.Bundle; import com.etesync.syncadapter.AccountSettings; @@ -32,6 +33,7 @@ import com.etesync.syncadapter.model.SyncEntry; import com.etesync.syncadapter.resource.LocalCollection; import com.etesync.syncadapter.resource.LocalResource; import com.etesync.syncadapter.ui.DebugInfoActivity; +import com.etesync.syncadapter.ui.ViewCollectionActivity; import org.apache.commons.collections4.ListUtils; @@ -51,6 +53,7 @@ import io.requery.sql.EntityDataStore; import okhttp3.OkHttpClient; import static com.etesync.syncadapter.Constants.KEY_ACCOUNT; +import static com.etesync.syncadapter.model.SyncEntry.Actions.ADD; abstract public class SyncManager { private static final int MAX_FETCH = 50; @@ -132,6 +135,8 @@ abstract public class SyncManager { protected abstract String getSyncErrorTitle(); + protected abstract String getSyncSuccessfullyTitle(); + @TargetApi(21) public void performSync() { int syncPhase = R.string.sync_phase_prepare; @@ -194,6 +199,8 @@ abstract public class SyncManager { App.log.info("Sync phase: " + context.getString(syncPhase)); postProcess(); + notifyUserOnSync(); + App.log.info("Finished sync with CTag=" + remoteCTag); } catch (IOException e) { App.log.log(Level.WARNING, "I/O exception during sync, trying again later", e); @@ -230,6 +237,47 @@ abstract public class SyncManager { } } + private void notifyUserOnSync() { + if (remoteEntries.isEmpty()) { + return; + } + NotificationHelper notificationHelper = new NotificationHelper(context, + String.valueOf(System.currentTimeMillis()), notificationId()); + + int deleted = 0; + int added = 0; + int changed = 0; + for (JournalEntryManager.Entry entry : remoteEntries) { + SyncEntry cEntry = SyncEntry.fromJournalEntry(crypto, entry); + SyncEntry.Actions action = cEntry.getAction(); + switch (action) { + case ADD: + added++; + break; + case DELETE: + deleted++; + break; + case CHANGE: + changed++; + break; + } + } + + Resources resources = context.getResources(); + Intent intent = ViewCollectionActivity.newIntent(context, account, info); + notificationHelper.notify(getSyncSuccessfullyTitle(), + String.format(context.getString(R.string.sync_successfully_modified), + resources.getQuantityString(R.plurals.sync_successfully, + remoteEntries.size(), remoteEntries.size())), + String.format(context.getString(R.string.sync_successfully_modified_full), + resources.getQuantityString(R.plurals.sync_successfully, + added, added), + resources.getQuantityString(R.plurals.sync_successfully, + changed, changed), + resources.getQuantityString(R.plurals.sync_successfully, + deleted, deleted)), + intent); + } /** * Prepares synchronization (for instance, allocates necessary resources). @@ -386,7 +434,7 @@ abstract public class SyncManager { for (LocalResource local : localDirty) { SyncEntry.Actions action; if (local.isLocalOnly()) { - action = SyncEntry.Actions.ADD; + action = ADD; } else { action = SyncEntry.Actions.CHANGE; } diff --git a/app/src/main/res/values/plurals.xml b/app/src/main/res/values/plurals.xml new file mode 100644 index 00000000..8549eacc --- /dev/null +++ b/app/src/main/res/values/plurals.xml @@ -0,0 +1,7 @@ + + + + %d entry + %d entries + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b18eb510..0d3fd53c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -303,6 +303,10 @@ post processing Authentication failed User is inactive + Calendar \"%s\" modified (%s) + Contacts modified (%s) + %s modified. + %s added.\n%s updated.\n%s deleted. EteSync: Connection security