diff --git a/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java b/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java index 3eff01fe5..93687f60d 100644 --- a/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -211,8 +211,8 @@ public class MessagingController implements Runnable { /** * List of messages that should be used for the inbox-style overview. * It's sorted from newest to oldest message. - * Don't modify this list directly, but use {@link addMessage} and - * {@link removeMatchingMessage} instead. + * Don't modify this list directly, but use {@link #addMessage(com.fsck.k9.mailstore.LocalMessage)} and + * {@link #removeMatchingMessage(android.content.Context, com.fsck.k9.activity.MessageReference)} instead. */ LinkedList messages; /** @@ -4853,6 +4853,7 @@ public class MessagingController implements Runnable { NotificationActionService.getReplyIntent(context, account, message.makeMessageReference())); } + // Mark Read on phone builder.addAction( platformSupportsLockScreenNotifications() ? R.drawable.ic_action_mark_as_read_dark_vector @@ -4864,15 +4865,51 @@ public class MessagingController implements Runnable { boolean showDeleteAction = deleteOption == NotificationQuickDelete.ALWAYS || (deleteOption == NotificationQuickDelete.FOR_SINGLE_MSG && newMessages == 1); + NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(); if (showDeleteAction) { // we need to pass the action directly to the activity, otherwise the // status bar won't be pulled up and we won't see the confirmation (if used) + + // Delete on phone builder.addAction( platformSupportsLockScreenNotifications() ? R.drawable.ic_action_delete_dark_vector : R.drawable.ic_action_delete_dark, context.getString(R.string.notification_action_delete), NotificationDeleteConfirmation.getIntent(context, account, allRefs)); + + // Delete on wear only if no confirmation is required + if (!K9.confirmDeleteFromNotification()) { + NotificationCompat.Action wearActionDelete = + new NotificationCompat.Action.Builder( + R.drawable.ic_action_delete_dark, + context.getString(R.string.notification_action_delete), + NotificationDeleteConfirmation.getIntent(context, account, allRefs)) + .build(); + builder.extend(wearableExtender.addAction(wearActionDelete)); + } + } + if (NotificationActionService.isArchiveAllMessagesWearAvaliable(context, account, data.messages)) { + + // Archive on wear + NotificationCompat.Action wearActionArchive = + new NotificationCompat.Action.Builder( + R.drawable.ic_action_delete_dark, + context.getString(R.string.notification_action_archive), + NotificationActionService.getArchiveAllMessagesIntent(context, account, allRefs)) + .build(); + builder.extend(wearableExtender.addAction(wearActionArchive)); + } + if (NotificationActionService.isSpamAllMessagesWearAvaliable(context, account, data.messages)) { + + // Archive on wear + NotificationCompat.Action wearActionSpam = + new NotificationCompat.Action.Builder( + R.drawable.ic_action_delete_dark, + context.getString(R.string.notification_action_spam), + NotificationActionService.getSpamAllMessagesIntent(context, account, allRefs)) + .build(); + builder.extend(wearableExtender.addAction(wearActionSpam)); } } else { String accountNotice = context.getString(R.string.notification_new_one_account_fmt, diff --git a/k9mail/src/main/java/com/fsck/k9/service/NotificationActionService.java b/k9mail/src/main/java/com/fsck/k9/service/NotificationActionService.java index 8b4e59440..3dd050884 100644 --- a/k9mail/src/main/java/com/fsck/k9/service/NotificationActionService.java +++ b/k9mail/src/main/java/com/fsck/k9/service/NotificationActionService.java @@ -2,6 +2,7 @@ package com.fsck.k9.service; import java.io.Serializable; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import com.fsck.k9.Account; @@ -18,10 +19,16 @@ import android.content.Context; import android.content.Intent; import android.util.Log; +/** + * Service called by actions in notifications. + * Provides a number of default actions to trigger. + */ public class NotificationActionService extends CoreService { private final static String REPLY_ACTION = "com.fsck.k9.service.NotificationActionService.REPLY_ACTION"; private final static String READ_ALL_ACTION = "com.fsck.k9.service.NotificationActionService.READ_ALL_ACTION"; private final static String DELETE_ALL_ACTION = "com.fsck.k9.service.NotificationActionService.DELETE_ALL_ACTION"; + private final static String ARCHIVE_ALL_ACTION = "com.fsck.k9.service.NotificationActionService.ARCHIVE_ALL_ACTION"; + private final static String SPAM_ALL_ACTION = "com.fsck.k9.service.NotificationActionService.SPAM_ALL_ACTION"; private final static String ACKNOWLEDGE_ACTION = "com.fsck.k9.service.NotificationActionService.ACKNOWLEDGE_ACTION"; private final static String EXTRA_ACCOUNT = "account"; @@ -63,6 +70,69 @@ public class NotificationActionService extends CoreService { return i; } + /** + * Check if for the given parameters the ArchiveAllMessages intent is possible for Android Wear. + * (No confirmation on the phone required and moving these messages to the spam-folder possible)
+ * Since we can not show a toast like on the phone screen, we must not offer actions that can not be performed. + * @see #getArchiveAllMessagesIntent(android.content.Context, com.fsck.k9.Account, java.io.Serializable) + * @param context the context to get a {@link MessagingController} + * @param account the account (must allow moving messages to allow true as a result) + * @param messages the messages to move to the spam folder (must be synchronized to allow true as a result) + * @return true if the ArchiveAllMessages intent is available for the given messages + */ + public static boolean isArchiveAllMessagesWearAvaliable(Context context, final Account account, final LinkedList messages) { + final MessagingController controller = MessagingController.getInstance(context); + return (account.getArchiveFolderName() != null && !(account.getArchiveFolderName().equals(account.getSpamFolderName()) && K9.confirmSpam()) && isMovePossible(controller, account, account.getSentFolderName(), messages)); + } + + public static PendingIntent getArchiveAllMessagesIntent(Context context, final Account account, final Serializable refs) { + Intent i = new Intent(context, NotificationActionService.class); + i.putExtra(EXTRA_ACCOUNT, account.getUuid()); + i.putExtra(EXTRA_MESSAGE_LIST, refs); + i.setAction(ARCHIVE_ALL_ACTION); + + return PendingIntent.getService(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT); + + } + + /** + * Check if for the given parameters the SpamAllMessages intent is possible for Android Wear. + * (No confirmation on the phone required and moving these messages to the spam-folder possible)
+ * Since we can not show a toast like on the phone screen, we must not offer actions that can not be performed. + * @see #getSpamAllMessagesIntent(android.content.Context, com.fsck.k9.Account, java.io.Serializable) + * @param context the context to get a {@link MessagingController} + * @param account the account (must allow moving messages to allow true as a result) + * @param messages the messages to move to the spam folder (must be synchronized to allow true as a result) + * @return true if the SpamAllMessages intent is available for the given messages + */ + public static boolean isSpamAllMessagesWearAvaliable(Context context, final Account account, final LinkedList messages) { + final MessagingController controller = MessagingController.getInstance(context); + return (account.getSpamFolderName() != null && !K9.confirmSpam() && isMovePossible(controller, account, account.getSentFolderName(), messages)); + } + + public static PendingIntent getSpamAllMessagesIntent(Context context, final Account account, final Serializable refs) { + Intent i = new Intent(context, NotificationActionService.class); + i.putExtra(EXTRA_ACCOUNT, account.getUuid()); + i.putExtra(EXTRA_MESSAGE_LIST, refs); + i.setAction(SPAM_ALL_ACTION); + + return PendingIntent.getService(context, account.getAccountNumber(), i, PendingIntent.FLAG_UPDATE_CURRENT); + } + + private static boolean isMovePossible(MessagingController controller, Account account, String dstFolder, List messages) { + if (!controller.isMoveCapable(account)) { + return false; + } + if (K9.FOLDER_NONE.equalsIgnoreCase(dstFolder)) { + return false; + } + for(LocalMessage messageToMove : messages) { + if (!controller.isMoveCapable(messageToMove)) { + return false; + } + } + return true; + } @Override public int startService(Intent intent, int startId) { if (K9.DEBUG) @@ -98,6 +168,59 @@ public class NotificationActionService extends CoreService { } controller.deleteMessages(messages, null); + } else if (ARCHIVE_ALL_ACTION.equals(action)) { + if (K9.DEBUG) + Log.i(K9.LOG_TAG, "NotificationActionService archiving messages"); + + List refs = + intent.getParcelableArrayListExtra(EXTRA_MESSAGE_LIST); + List messages = new ArrayList(); + + for (MessageReference ref : refs) { + LocalMessage m = ref.restoreToLocalMessage(this.getApplicationContext()); + if (m != null) { + messages.add(m); + } + } + + String dstFolder = account.getArchiveFolderName(); + if (dstFolder != null + && !(dstFolder.equals(account.getSpamFolderName()) && K9.confirmSpam()) + && isMovePossible(controller, account, dstFolder, messages)) { + for(LocalMessage messageToMove : messages) { + if (!controller.isMoveCapable(messageToMove)) { + //Toast toast = Toast.makeText(getActivity(), R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG); + //toast.show(); + continue; + } + String srcFolder = messageToMove.getFolder().getName(); + controller.moveMessage(account, srcFolder, messageToMove, dstFolder, null); + } + } + } else if (SPAM_ALL_ACTION.equals(action)) { + if (K9.DEBUG) + Log.i(K9.LOG_TAG, "NotificationActionService moving messages to spam"); + + List refs = + intent.getParcelableArrayListExtra(EXTRA_MESSAGE_LIST); + List messages = new ArrayList(); + + for (MessageReference ref : refs) { + LocalMessage m = ref.restoreToLocalMessage(this); + if (m != null) { + messages.add(m); + } + } + + String dstFolder = account.getSpamFolderName(); + if (dstFolder != null + && !K9.confirmSpam() + && isMovePossible(controller, account, dstFolder, messages)) { + for(LocalMessage messageToMove : messages) { + String srcFolder = messageToMove.getFolder().getName(); + controller.moveMessage(account, srcFolder, messageToMove, dstFolder, null); + } + } } else if (REPLY_ACTION.equals(action)) { if (K9.DEBUG) Log.i(K9.LOG_TAG, "NotificationActionService initiating reply"); diff --git a/k9mail/src/main/res/values-de/strings.xml b/k9mail/src/main/res/values-de/strings.xml index d006470e8..ed79da500 100644 --- a/k9mail/src/main/res/values-de/strings.xml +++ b/k9mail/src/main/res/values-de/strings.xml @@ -167,6 +167,8 @@ Um Fehler zu melden, neue Funktionen vorzuschlagen oder Fragen zu stellen, besuc Antworten Gelesen Löschen + Spam + Archivieren Zertifikatsproblem (%s) Überprüfen Sie Ihre Servereinstellungen Neue E-Mails in %s:%s werden abgerufen diff --git a/k9mail/src/main/res/values/strings.xml b/k9mail/src/main/res/values/strings.xml index 5d977423d..ad916134b 100644 --- a/k9mail/src/main/res/values/strings.xml +++ b/k9mail/src/main/res/values/strings.xml @@ -210,6 +210,8 @@ Please submit bug reports, contribute new features and ask questions at Reply Mark Read Delete + Archive + Spam Certificate error for %s Check your server settings @@ -1147,4 +1149,5 @@ Please submit bug reports, contribute new features and ask questions at Incomplete message Click \'Download complete message\' to allow decryption. +