Merge pull request #3478 from k9mail/decouple_notification_code
Decouple notification code from Activities
This commit is contained in:
commit
0dd464d9ad
10 changed files with 381 additions and 283 deletions
|
@ -3,15 +3,12 @@ package com.fsck.k9.notification;
|
|||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationCompat.BigTextStyle;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.core.R;
|
||||
import com.fsck.k9.activity.setup.AccountSetupIncoming;
|
||||
import com.fsck.k9.activity.setup.AccountSetupOutgoing;
|
||||
|
||||
import static com.fsck.k9.notification.NotificationController.NOTIFICATION_LED_BLINK_FAST;
|
||||
import static com.fsck.k9.notification.NotificationController.NOTIFICATION_LED_FAILURE_COLOR;
|
||||
|
@ -19,10 +16,13 @@ import static com.fsck.k9.notification.NotificationController.NOTIFICATION_LED_F
|
|||
|
||||
class AuthenticationErrorNotifications {
|
||||
private final NotificationController controller;
|
||||
private final NotificationActionCreator actionCreator;
|
||||
|
||||
|
||||
public AuthenticationErrorNotifications(NotificationController controller) {
|
||||
public AuthenticationErrorNotifications(NotificationController controller,
|
||||
NotificationActionCreator actionCreator) {
|
||||
this.controller = controller;
|
||||
this.actionCreator = actionCreator;
|
||||
}
|
||||
|
||||
public void showAuthenticationErrorNotification(Account account, boolean incoming) {
|
||||
|
@ -58,12 +58,8 @@ class AuthenticationErrorNotifications {
|
|||
}
|
||||
|
||||
PendingIntent createContentIntent(Context context, Account account, boolean incoming) {
|
||||
Intent editServerSettingsIntent = incoming ?
|
||||
AccountSetupIncoming.intentActionEditIncomingSettings(context, account) :
|
||||
AccountSetupOutgoing.intentActionEditOutgoingSettings(context, account);
|
||||
|
||||
return PendingIntent.getActivity(context, account.getAccountNumber(), editServerSettingsIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
return incoming ? actionCreator.getEditIncomingServerSettingsIntent(account) :
|
||||
actionCreator.getEditOutgoingServerSettingsIntent(account);
|
||||
}
|
||||
|
||||
private NotificationManagerCompat getNotificationManager() {
|
||||
|
|
|
@ -3,14 +3,11 @@ package com.fsck.k9.notification;
|
|||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.core.R;
|
||||
import com.fsck.k9.activity.setup.AccountSetupIncoming;
|
||||
import com.fsck.k9.activity.setup.AccountSetupOutgoing;
|
||||
|
||||
import static com.fsck.k9.notification.NotificationController.NOTIFICATION_LED_BLINK_FAST;
|
||||
import static com.fsck.k9.notification.NotificationController.NOTIFICATION_LED_FAILURE_COLOR;
|
||||
|
@ -18,10 +15,12 @@ import static com.fsck.k9.notification.NotificationController.NOTIFICATION_LED_F
|
|||
|
||||
class CertificateErrorNotifications {
|
||||
private final NotificationController controller;
|
||||
private final NotificationActionCreator actionCreator;
|
||||
|
||||
|
||||
public CertificateErrorNotifications(NotificationController controller) {
|
||||
public CertificateErrorNotifications(NotificationController controller, NotificationActionCreator actionCreator) {
|
||||
this.controller = controller;
|
||||
this.actionCreator = actionCreator;
|
||||
}
|
||||
|
||||
public void showCertificateErrorNotification(Account account, boolean incoming) {
|
||||
|
@ -56,12 +55,9 @@ class CertificateErrorNotifications {
|
|||
}
|
||||
|
||||
PendingIntent createContentIntent(Context context, Account account, boolean incoming) {
|
||||
Intent editServerSettingsIntent = incoming ?
|
||||
AccountSetupIncoming.intentActionEditIncomingSettings(context, account) :
|
||||
AccountSetupOutgoing.intentActionEditOutgoingSettings(context, account);
|
||||
|
||||
return PendingIntent.getActivity(context, account.getAccountNumber(), editServerSettingsIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
return incoming ?
|
||||
actionCreator.getEditIncomingServerSettingsIntent(account) :
|
||||
actionCreator.getEditOutgoingServerSettingsIntent(account);
|
||||
}
|
||||
|
||||
private int getCertificateErrorNotificationIcon() {
|
||||
|
|
|
@ -5,281 +5,52 @@ import java.util.List;
|
|||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.activity.Accounts;
|
||||
import com.fsck.k9.activity.FolderList;
|
||||
import com.fsck.k9.activity.MessageList;
|
||||
import com.fsck.k9.activity.MessageReference;
|
||||
import com.fsck.k9.activity.NotificationDeleteConfirmation;
|
||||
import com.fsck.k9.activity.compose.MessageActions;
|
||||
import com.fsck.k9.search.LocalSearch;
|
||||
|
||||
|
||||
/**
|
||||
* This class contains methods to create the {@link PendingIntent}s for the actions of new mail notifications.
|
||||
* <p/>
|
||||
* <strong>Note:</strong>
|
||||
* We need to take special care to ensure the {@code PendingIntent}s are unique as defined in the documentation of
|
||||
* {@link PendingIntent}. Otherwise selecting a notification action might perform the action on the wrong message.
|
||||
* <p/>
|
||||
* We use the notification ID as {@code requestCode} argument to ensure each notification/action pair gets a unique
|
||||
* {@code PendingIntent}.
|
||||
*/
|
||||
class NotificationActionCreator {
|
||||
private final Context context;
|
||||
public interface NotificationActionCreator {
|
||||
PendingIntent createViewMessagePendingIntent(MessageReference messageReference, int notificationId);
|
||||
|
||||
PendingIntent createViewFolderPendingIntent(Account account, String folderServerId, int notificationId);
|
||||
|
||||
public NotificationActionCreator(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
PendingIntent createViewMessagesPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId);
|
||||
|
||||
public PendingIntent createViewMessagePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
TaskStackBuilder stack = buildMessageViewBackStack(messageReference);
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
PendingIntent createViewFolderListPendingIntent(Account account, int notificationId);
|
||||
|
||||
public PendingIntent createViewFolderPendingIntent(Account account, String folderServerId, int notificationId) {
|
||||
TaskStackBuilder stack = buildMessageListBackStack(account, folderServerId);
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
PendingIntent createDismissAllMessagesPendingIntent(Account account, int notificationId);
|
||||
|
||||
public PendingIntent createViewMessagesPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
PendingIntent createDismissMessagePendingIntent(Context context, MessageReference messageReference,
|
||||
int notificationId);
|
||||
|
||||
TaskStackBuilder stack;
|
||||
if (account.goToUnreadMessageSearch()) {
|
||||
stack = buildUnreadBackStack(account);
|
||||
} else {
|
||||
String folderServerId = getFolderServerIdOfAllMessages(messageReferences);
|
||||
PendingIntent createReplyPendingIntent(MessageReference messageReference, int notificationId);
|
||||
|
||||
if (folderServerId == null) {
|
||||
stack = buildFolderListBackStack(account);
|
||||
} else {
|
||||
stack = buildMessageListBackStack(account, folderServerId);
|
||||
}
|
||||
}
|
||||
PendingIntent createMarkMessageAsReadPendingIntent(MessageReference messageReference, int notificationId);
|
||||
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
PendingIntent createMarkAllAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId);
|
||||
|
||||
public PendingIntent createViewFolderListPendingIntent(Account account, int notificationId) {
|
||||
TaskStackBuilder stack = buildFolderListBackStack(account);
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
PendingIntent getMarkAllAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId);
|
||||
|
||||
public PendingIntent createDismissAllMessagesPendingIntent(Account account, int notificationId) {
|
||||
Intent intent = NotificationActionService.createDismissAllMessagesIntent(context, account);
|
||||
PendingIntent getEditIncomingServerSettingsIntent(Account account);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
PendingIntent getEditOutgoingServerSettingsIntent(Account account);
|
||||
|
||||
public PendingIntent createDismissMessagePendingIntent(Context context, MessageReference messageReference,
|
||||
int notificationId) {
|
||||
PendingIntent createDeleteMessagePendingIntent(MessageReference messageReference, int notificationId);
|
||||
|
||||
Intent intent = NotificationActionService.createDismissMessageIntent(context, messageReference);
|
||||
PendingIntent createDeleteAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
PendingIntent getDeleteAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId);
|
||||
|
||||
public PendingIntent createReplyPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = MessageActions.getActionReplyIntent(context, messageReference);
|
||||
PendingIntent createArchiveMessagePendingIntent(MessageReference messageReference, int notificationId);
|
||||
|
||||
return PendingIntent.getActivity(context, notificationId, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
PendingIntent createArchiveAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId);
|
||||
|
||||
public PendingIntent createMarkMessageAsReadPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createMarkMessageAsReadIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
public PendingIntent createMarkAllAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
return getMarkAsReadPendingIntent(account, messageReferences, notificationId, context,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
public PendingIntent getMarkAllAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
return getMarkAsReadPendingIntent(account, messageReferences, notificationId, context,
|
||||
PendingIntent.FLAG_NO_CREATE);
|
||||
}
|
||||
|
||||
private PendingIntent getMarkAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId, Context context, int flags) {
|
||||
String accountUuid = account.getUuid();
|
||||
Intent intent = NotificationActionService.createMarkAllAsReadIntent(context, accountUuid, messageReferences);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent, flags);
|
||||
}
|
||||
|
||||
public PendingIntent createDeleteMessagePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
if (K9.confirmDeleteFromNotification()) {
|
||||
return createDeleteConfirmationPendingIntent(messageReference, notificationId);
|
||||
} else {
|
||||
return createDeleteServicePendingIntent(messageReference, notificationId);
|
||||
}
|
||||
}
|
||||
|
||||
private PendingIntent createDeleteServicePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createDeleteMessageIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
private PendingIntent createDeleteConfirmationPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationDeleteConfirmation.getIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public PendingIntent createDeleteAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
if (K9.confirmDeleteFromNotification()) {
|
||||
return getDeleteAllConfirmationPendingIntent(messageReferences, notificationId,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
} else {
|
||||
return getDeleteAllServicePendingIntent(account, messageReferences, notificationId,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
public PendingIntent getDeleteAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
if (K9.confirmDeleteFromNotification()) {
|
||||
return getDeleteAllConfirmationPendingIntent(messageReferences, notificationId,
|
||||
PendingIntent.FLAG_NO_CREATE);
|
||||
} else {
|
||||
return getDeleteAllServicePendingIntent(account, messageReferences, notificationId,
|
||||
PendingIntent.FLAG_NO_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
private PendingIntent getDeleteAllConfirmationPendingIntent(List<MessageReference> messageReferences,
|
||||
int notificationId, int flags) {
|
||||
Intent intent = NotificationDeleteConfirmation.getIntent(context, messageReferences);
|
||||
|
||||
return PendingIntent.getActivity(context, notificationId, intent, flags);
|
||||
}
|
||||
|
||||
private PendingIntent getDeleteAllServicePendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId, int flags) {
|
||||
String accountUuid = account.getUuid();
|
||||
Intent intent = NotificationActionService.createDeleteAllMessagesIntent(
|
||||
context, accountUuid, messageReferences);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent, flags);
|
||||
}
|
||||
|
||||
public PendingIntent createArchiveMessagePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createArchiveMessageIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
public PendingIntent createArchiveAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
Intent intent = NotificationActionService.createArchiveAllIntent(context, account, messageReferences);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
public PendingIntent createMarkMessageAsSpamPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createMarkMessageAsSpamIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildAccountsBackStack() {
|
||||
TaskStackBuilder stack = TaskStackBuilder.create(context);
|
||||
if (!skipAccountsInBackStack()) {
|
||||
Intent intent = new Intent(context, Accounts.class);
|
||||
intent.putExtra(Accounts.EXTRA_STARTUP, false);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildFolderListBackStack(Account account) {
|
||||
TaskStackBuilder stack = buildAccountsBackStack();
|
||||
|
||||
Intent intent = FolderList.actionHandleAccountIntent(context, account, false);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildUnreadBackStack(final Account account) {
|
||||
TaskStackBuilder stack = buildAccountsBackStack();
|
||||
|
||||
LocalSearch search = Accounts.createUnreadSearch(context, account);
|
||||
Intent intent = MessageList.intentDisplaySearch(context, search, true, false, false);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildMessageListBackStack(Account account, String folderServerId) {
|
||||
TaskStackBuilder stack = skipFolderListInBackStack(account, folderServerId) ?
|
||||
buildAccountsBackStack() : buildFolderListBackStack(account);
|
||||
|
||||
LocalSearch search = new LocalSearch(folderServerId);
|
||||
search.addAllowedFolder(folderServerId);
|
||||
search.addAccountUuid(account.getUuid());
|
||||
Intent intent = MessageList.intentDisplaySearch(context, search, false, true, true);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildMessageViewBackStack(MessageReference message) {
|
||||
Account account = Preferences.getPreferences(context).getAccount(message.getAccountUuid());
|
||||
String folderServerId = message.getFolderServerId();
|
||||
TaskStackBuilder stack = buildMessageListBackStack(account, folderServerId);
|
||||
|
||||
Intent intent = MessageList.actionDisplayMessageIntent(context, message);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private String getFolderServerIdOfAllMessages(List<MessageReference> messageReferences) {
|
||||
MessageReference firstMessage = messageReferences.get(0);
|
||||
String folderServerId = firstMessage.getFolderServerId();
|
||||
|
||||
for (MessageReference messageReference : messageReferences) {
|
||||
if (!TextUtils.equals(folderServerId, messageReference.getFolderServerId())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return folderServerId;
|
||||
}
|
||||
|
||||
private boolean skipFolderListInBackStack(Account account, String folderServerId) {
|
||||
return folderServerId != null && folderServerId.equals(account.getAutoExpandFolder());
|
||||
}
|
||||
|
||||
private boolean skipAccountsInBackStack() {
|
||||
return Preferences.getPreferences(context).getAccounts().size() == 1;
|
||||
}
|
||||
PendingIntent createMarkMessageAsSpamPendingIntent(MessageReference messageReference, int notificationId);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.support.v4.app.NotificationManagerCompat;
|
|||
import android.text.TextUtils;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.DI;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.activity.MessageReference;
|
||||
import com.fsck.k9.mail.Folder;
|
||||
|
@ -53,9 +54,9 @@ public class NotificationController {
|
|||
this.context = context;
|
||||
this.notificationManager = notificationManager;
|
||||
|
||||
NotificationActionCreator actionBuilder = new NotificationActionCreator(context);
|
||||
certificateErrorNotifications = new CertificateErrorNotifications(this);
|
||||
authenticationErrorNotifications = new AuthenticationErrorNotifications(this);
|
||||
NotificationActionCreator actionBuilder = DI.get(NotificationActionCreator.class);
|
||||
certificateErrorNotifications = new CertificateErrorNotifications(this, actionBuilder);
|
||||
authenticationErrorNotifications = new AuthenticationErrorNotifications(this, actionBuilder);
|
||||
syncNotifications = new SyncNotifications(this, actionBuilder);
|
||||
sendFailedNotifications = new SendFailedNotifications(this, actionBuilder);
|
||||
newMailNotifications = NewMailNotifications.newInstance(this, actionBuilder);
|
||||
|
|
|
@ -2,14 +2,15 @@ package com.fsck.k9
|
|||
|
||||
import android.arch.lifecycle.Lifecycle
|
||||
import android.arch.lifecycle.LifecycleOwner
|
||||
import com.fsck.k9.notification.NotificationActionCreator
|
||||
import com.fsck.k9.ui.endtoend.AutocryptKeyTransferActivity
|
||||
import com.fsck.k9.ui.endtoend.AutocryptKeyTransferViewModel
|
||||
import com.fsck.k9.ui.endtoend.AutocryptSetupMessageLiveEvent
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import org.junit.Test
|
||||
import org.koin.Koin
|
||||
import org.koin.dsl.module.applicationContext
|
||||
import org.koin.log.PrintLogger
|
||||
import org.koin.standalone.StandAloneContext
|
||||
import org.koin.test.dryRun
|
||||
|
||||
class DependencyInjectionTest : K9RobolectricTest() {
|
||||
|
@ -21,6 +22,11 @@ class DependencyInjectionTest : K9RobolectricTest() {
|
|||
fun testDependencyTree() {
|
||||
Koin.logger = PrintLogger()
|
||||
|
||||
// NOTE: Users of the core module will have to provide these dependencies.
|
||||
StandAloneContext.loadKoinModules(applicationContext {
|
||||
bean { mock<NotificationActionCreator>() }
|
||||
})
|
||||
|
||||
dryRun {
|
||||
mapOf(
|
||||
"lifecycleOwner" to lifecycleOwner,
|
||||
|
|
|
@ -134,7 +134,7 @@ public class AuthenticationErrorNotificationsTest extends RobolectricTest {
|
|||
|
||||
class TestAuthenticationErrorNotifications extends AuthenticationErrorNotifications {
|
||||
public TestAuthenticationErrorNotifications() {
|
||||
super(controller);
|
||||
super(controller, mock(NotificationActionCreator.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -134,7 +134,7 @@ public class CertificateErrorNotificationsTest extends RobolectricTest {
|
|||
|
||||
class TestCertificateErrorNotifications extends CertificateErrorNotifications {
|
||||
public TestCertificateErrorNotifications() {
|
||||
super(controller);
|
||||
super(controller, mock(NotificationActionCreator.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.fsck.k9
|
|||
|
||||
import com.fsck.k9.external.BroadcastSenderListener
|
||||
import com.fsck.k9.external.externalModule
|
||||
import com.fsck.k9.notification.notificationModule
|
||||
import com.fsck.k9.widget.list.MessageListWidgetUpdateListener
|
||||
import com.fsck.k9.widget.list.messageListWidgetModule
|
||||
import com.fsck.k9.widget.unread.UnreadWidgetUpdateListener
|
||||
|
@ -22,5 +23,6 @@ val appModules = listOf(
|
|||
mainAppModule,
|
||||
externalModule,
|
||||
messageListWidgetModule,
|
||||
unreadWidgetModule
|
||||
unreadWidgetModule,
|
||||
notificationModule
|
||||
)
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
package com.fsck.k9.notification;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.activity.Accounts;
|
||||
import com.fsck.k9.activity.FolderList;
|
||||
import com.fsck.k9.activity.MessageList;
|
||||
import com.fsck.k9.activity.MessageReference;
|
||||
import com.fsck.k9.activity.NotificationDeleteConfirmation;
|
||||
import com.fsck.k9.activity.compose.MessageActions;
|
||||
import com.fsck.k9.activity.setup.AccountSetupIncoming;
|
||||
import com.fsck.k9.activity.setup.AccountSetupOutgoing;
|
||||
import com.fsck.k9.search.LocalSearch;
|
||||
|
||||
|
||||
/**
|
||||
* This class contains methods to create the {@link PendingIntent}s for the actions of our notifications.
|
||||
* <p/>
|
||||
* <strong>Note:</strong>
|
||||
* We need to take special care to ensure the {@code PendingIntent}s are unique as defined in the documentation of
|
||||
* {@link PendingIntent}. Otherwise selecting a notification action might perform the action on the wrong message.
|
||||
* <p/>
|
||||
* We use the notification ID as {@code requestCode} argument to ensure each notification/action pair gets a unique
|
||||
* {@code PendingIntent}.
|
||||
*/
|
||||
class K9NotificationActionCreator implements NotificationActionCreator {
|
||||
private final Context context;
|
||||
|
||||
|
||||
public K9NotificationActionCreator(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createViewMessagePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
TaskStackBuilder stack = buildMessageViewBackStack(messageReference);
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createViewFolderPendingIntent(Account account, String folderServerId, int notificationId) {
|
||||
TaskStackBuilder stack = buildMessageListBackStack(account, folderServerId);
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createViewMessagesPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
|
||||
TaskStackBuilder stack;
|
||||
if (account.goToUnreadMessageSearch()) {
|
||||
stack = buildUnreadBackStack(account);
|
||||
} else {
|
||||
String folderServerId = getFolderServerIdOfAllMessages(messageReferences);
|
||||
|
||||
if (folderServerId == null) {
|
||||
stack = buildFolderListBackStack(account);
|
||||
} else {
|
||||
stack = buildMessageListBackStack(account, folderServerId);
|
||||
}
|
||||
}
|
||||
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createViewFolderListPendingIntent(Account account, int notificationId) {
|
||||
TaskStackBuilder stack = buildFolderListBackStack(account);
|
||||
return stack.getPendingIntent(notificationId, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createDismissAllMessagesPendingIntent(Account account, int notificationId) {
|
||||
Intent intent = NotificationActionService.createDismissAllMessagesIntent(context, account);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createDismissMessagePendingIntent(Context context, MessageReference messageReference,
|
||||
int notificationId) {
|
||||
|
||||
Intent intent = NotificationActionService.createDismissMessageIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createReplyPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = MessageActions.getActionReplyIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getActivity(context, notificationId, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createMarkMessageAsReadPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createMarkMessageAsReadIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createMarkAllAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
return getMarkAsReadPendingIntent(account, messageReferences, notificationId, context,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent getMarkAllAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
return getMarkAsReadPendingIntent(account, messageReferences, notificationId, context,
|
||||
PendingIntent.FLAG_NO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent getEditIncomingServerSettingsIntent(Account account) {
|
||||
Intent intent = AccountSetupIncoming.intentActionEditIncomingSettings(context, account);
|
||||
|
||||
return PendingIntent.getActivity(context, account.getAccountNumber(), intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent getEditOutgoingServerSettingsIntent(Account account) {
|
||||
Intent intent = AccountSetupOutgoing.intentActionEditOutgoingSettings(context, account);
|
||||
|
||||
return PendingIntent.getActivity(context, account.getAccountNumber(), intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
private PendingIntent getMarkAsReadPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId, Context context, int flags) {
|
||||
String accountUuid = account.getUuid();
|
||||
Intent intent = NotificationActionService.createMarkAllAsReadIntent(context, accountUuid, messageReferences);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createDeleteMessagePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
if (K9.confirmDeleteFromNotification()) {
|
||||
return createDeleteConfirmationPendingIntent(messageReference, notificationId);
|
||||
} else {
|
||||
return createDeleteServicePendingIntent(messageReference, notificationId);
|
||||
}
|
||||
}
|
||||
|
||||
private PendingIntent createDeleteServicePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createDeleteMessageIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
private PendingIntent createDeleteConfirmationPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationDeleteConfirmation.getIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createDeleteAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
if (K9.confirmDeleteFromNotification()) {
|
||||
return getDeleteAllConfirmationPendingIntent(messageReferences, notificationId,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
} else {
|
||||
return getDeleteAllServicePendingIntent(account, messageReferences, notificationId,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent getDeleteAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
if (K9.confirmDeleteFromNotification()) {
|
||||
return getDeleteAllConfirmationPendingIntent(messageReferences, notificationId,
|
||||
PendingIntent.FLAG_NO_CREATE);
|
||||
} else {
|
||||
return getDeleteAllServicePendingIntent(account, messageReferences, notificationId,
|
||||
PendingIntent.FLAG_NO_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
private PendingIntent getDeleteAllConfirmationPendingIntent(List<MessageReference> messageReferences,
|
||||
int notificationId, int flags) {
|
||||
Intent intent = NotificationDeleteConfirmation.getIntent(context, messageReferences);
|
||||
|
||||
return PendingIntent.getActivity(context, notificationId, intent, flags);
|
||||
}
|
||||
|
||||
private PendingIntent getDeleteAllServicePendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId, int flags) {
|
||||
String accountUuid = account.getUuid();
|
||||
Intent intent = NotificationActionService.createDeleteAllMessagesIntent(
|
||||
context, accountUuid, messageReferences);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createArchiveMessagePendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createArchiveMessageIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createArchiveAllPendingIntent(Account account, List<MessageReference> messageReferences,
|
||||
int notificationId) {
|
||||
Intent intent = NotificationActionService.createArchiveAllIntent(context, account, messageReferences);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent createMarkMessageAsSpamPendingIntent(MessageReference messageReference, int notificationId) {
|
||||
Intent intent = NotificationActionService.createMarkMessageAsSpamIntent(context, messageReference);
|
||||
|
||||
return PendingIntent.getService(context, notificationId, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildAccountsBackStack() {
|
||||
TaskStackBuilder stack = TaskStackBuilder.create(context);
|
||||
if (!skipAccountsInBackStack()) {
|
||||
Intent intent = new Intent(context, Accounts.class);
|
||||
intent.putExtra(Accounts.EXTRA_STARTUP, false);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildFolderListBackStack(Account account) {
|
||||
TaskStackBuilder stack = buildAccountsBackStack();
|
||||
|
||||
Intent intent = FolderList.actionHandleAccountIntent(context, account, false);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildUnreadBackStack(final Account account) {
|
||||
TaskStackBuilder stack = buildAccountsBackStack();
|
||||
|
||||
LocalSearch search = Accounts.createUnreadSearch(context, account);
|
||||
Intent intent = MessageList.intentDisplaySearch(context, search, true, false, false);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildMessageListBackStack(Account account, String folderServerId) {
|
||||
TaskStackBuilder stack = skipFolderListInBackStack(account, folderServerId) ?
|
||||
buildAccountsBackStack() : buildFolderListBackStack(account);
|
||||
|
||||
LocalSearch search = new LocalSearch(folderServerId);
|
||||
search.addAllowedFolder(folderServerId);
|
||||
search.addAccountUuid(account.getUuid());
|
||||
Intent intent = MessageList.intentDisplaySearch(context, search, false, true, true);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private TaskStackBuilder buildMessageViewBackStack(MessageReference message) {
|
||||
Account account = Preferences.getPreferences(context).getAccount(message.getAccountUuid());
|
||||
String folderServerId = message.getFolderServerId();
|
||||
TaskStackBuilder stack = buildMessageListBackStack(account, folderServerId);
|
||||
|
||||
Intent intent = MessageList.actionDisplayMessageIntent(context, message);
|
||||
|
||||
stack.addNextIntent(intent);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private String getFolderServerIdOfAllMessages(List<MessageReference> messageReferences) {
|
||||
MessageReference firstMessage = messageReferences.get(0);
|
||||
String folderServerId = firstMessage.getFolderServerId();
|
||||
|
||||
for (MessageReference messageReference : messageReferences) {
|
||||
if (!TextUtils.equals(folderServerId, messageReference.getFolderServerId())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return folderServerId;
|
||||
}
|
||||
|
||||
private boolean skipFolderListInBackStack(Account account, String folderServerId) {
|
||||
return folderServerId != null && folderServerId.equals(account.getAutoExpandFolder());
|
||||
}
|
||||
|
||||
private boolean skipAccountsInBackStack() {
|
||||
return Preferences.getPreferences(context).getAccounts().size() == 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.fsck.k9.notification
|
||||
|
||||
import org.koin.dsl.module.applicationContext
|
||||
|
||||
val notificationModule = applicationContext {
|
||||
bean { K9NotificationActionCreator(get()) as NotificationActionCreator }
|
||||
}
|
Loading…
Reference in a new issue