package com.fsck.k9.notification; import java.util.Arrays; import java.util.List; import android.app.Application; import android.app.Notification; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat.BigTextStyle; import android.support.v4.app.NotificationCompat.Builder; import android.support.v4.app.NotificationCompat.InboxStyle; import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.K9.NotificationHideSubject; import com.fsck.k9.K9.NotificationQuickDelete; import com.fsck.k9.K9RobolectricTestRunner; import com.fsck.k9.NotificationSetting; import com.fsck.k9.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.RuntimeEnvironment; import static com.fsck.k9.MockHelper.mockBuilder; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(K9RobolectricTestRunner.class) public class DeviceNotificationsTest { private static final int UNREAD_MESSAGE_COUNT = 42; private static final int NEW_MESSAGE_COUNT = 2; private static final String ACCOUNT_NAME = "accountName"; private static final int ACCOUNT_NUMBER = 3; private static final int ACCOUNT_COLOR = 0xABCDEF; private static final String SUMMARY = "summary"; private static final String PREVIEW = "preview"; private static final String SUBJECT = "subject"; private static final String SENDER = "sender"; private static final String SUMMARY_2 = "summary2"; private static final String PREVIEW_2 = "preview2"; private static final String SUBJECT_2 = "subject2"; private static final String SENDER_2 = "sender2"; private static final int NOTIFICATION_ID = 23; private static final Notification FAKE_NOTIFICATION = mock(Notification.class); private Account account; private NotificationData notificationData; private TestDeviceNotifications notifications; private Builder builder; private Builder builder2 = mockBuilder(Builder.class); private LockScreenNotification lockScreenNotification; @Before public void setUp() throws Exception { account = createFakeAccount(); notificationData = createFakeNotificationData(account); builder = createFakeNotificationBuilder(); lockScreenNotification = mock(LockScreenNotification.class); notifications = createDeviceNotifications(builder, lockScreenNotification); } @Test public void buildSummaryNotification_withPrivacyModeActive() throws Exception { K9.setNotificationHideSubject(NotificationHideSubject.ALWAYS); Notification result = notifications.buildSummaryNotification(account, notificationData, false); verify(builder).setSmallIcon(R.drawable.notification_icon_new_mail); verify(builder).setColor(ACCOUNT_COLOR); verify(builder).setAutoCancel(true); verify(builder).setNumber(UNREAD_MESSAGE_COUNT); verify(builder).setTicker("New mail"); verify(builder).setContentText("New mail"); verify(builder).setContentTitle(UNREAD_MESSAGE_COUNT + " Unread (" + ACCOUNT_NAME + ")"); verify(lockScreenNotification).configureLockScreenNotification(builder, notificationData); assertEquals(FAKE_NOTIFICATION, result); } @Test public void buildSummaryNotification_withSingleMessageNotification() throws Exception { K9.setNotificationHideSubject(NotificationHideSubject.NEVER); K9.setNotificationQuickDeleteBehaviour(NotificationQuickDelete.ALWAYS); when(notificationData.isSingleMessageNotification()).thenReturn(true); Notification result = notifications.buildSummaryNotification(account, notificationData, false); verify(builder).setSmallIcon(R.drawable.notification_icon_new_mail); verify(builder).setColor(ACCOUNT_COLOR); verify(builder).setAutoCancel(true); verify(builder).setTicker(SUMMARY); verify(builder).setContentText(SUBJECT); verify(builder).setContentTitle(SENDER); verify(builder).setStyle(notifications.bigTextStyle); verify(notifications.bigTextStyle).bigText(PREVIEW); verify(builder).addAction(R.drawable.notification_action_reply, "Reply", null); verify(builder).addAction(R.drawable.notification_action_mark_as_read, "Mark Read", null); verify(builder).addAction(R.drawable.notification_action_delete, "Delete", null); verify(lockScreenNotification).configureLockScreenNotification(builder, notificationData); assertEquals(FAKE_NOTIFICATION, result); } @Test public void buildSummaryNotification_withMultiMessageNotification() throws Exception { K9.setNotificationHideSubject(NotificationHideSubject.NEVER); K9.setNotificationQuickDeleteBehaviour(NotificationQuickDelete.ALWAYS); when(notificationData.isSingleMessageNotification()).thenReturn(false); when(notificationData.containsStarredMessages()).thenReturn(true); Notification result = notifications.buildSummaryNotification(account, notificationData, false); verify(builder).setSmallIcon(R.drawable.notification_icon_new_mail); verify(builder).setColor(ACCOUNT_COLOR); verify(builder).setAutoCancel(true); verify(builder).setTicker(SUMMARY); verify(builder).setContentTitle(NEW_MESSAGE_COUNT + " new messages"); verify(builder).setSubText(ACCOUNT_NAME); verify(builder).setGroup("newMailNotifications-" + ACCOUNT_NUMBER); verify(builder).setGroupSummary(true); verify(builder).setPriority(NotificationCompat.PRIORITY_HIGH); verify(builder).setStyle(notifications.inboxStyle); verify(notifications.inboxStyle).setBigContentTitle(NEW_MESSAGE_COUNT + " new messages"); verify(notifications.inboxStyle).setSummaryText(ACCOUNT_NAME); verify(notifications.inboxStyle).addLine(SUMMARY); verify(notifications.inboxStyle).addLine(SUMMARY_2); verify(builder).addAction(R.drawable.notification_action_mark_as_read, "Mark Read", null); verify(builder).addAction(R.drawable.notification_action_delete, "Delete", null); verify(lockScreenNotification).configureLockScreenNotification(builder, notificationData); assertEquals(FAKE_NOTIFICATION, result); } @Test public void buildSummaryNotification_withAdditionalMessages() throws Exception { K9.setNotificationHideSubject(NotificationHideSubject.NEVER); K9.setNotificationQuickDeleteBehaviour(NotificationQuickDelete.ALWAYS); when(notificationData.isSingleMessageNotification()).thenReturn(false); when(notificationData.hasSummaryOverflowMessages()).thenReturn(true); when(notificationData.getSummaryOverflowMessagesCount()).thenReturn(23); notifications.buildSummaryNotification(account, notificationData, false); verify(notifications.inboxStyle).setSummaryText("+ 23 more on " + ACCOUNT_NAME); } @Test public void buildSummaryNotification_withoutDeleteAllAction() throws Exception { K9.setNotificationHideSubject(NotificationHideSubject.NEVER); K9.setNotificationQuickDeleteBehaviour(NotificationQuickDelete.NEVER); when(notificationData.isSingleMessageNotification()).thenReturn(false); notifications.buildSummaryNotification(account, notificationData, false); verify(builder, never()).addAction(R.drawable.notification_action_delete, "Delete", null); } @Test public void buildSummaryNotification_withoutDeleteAction() throws Exception { K9.setNotificationHideSubject(NotificationHideSubject.NEVER); K9.setNotificationQuickDeleteBehaviour(NotificationQuickDelete.NEVER); when(notificationData.isSingleMessageNotification()).thenReturn(true); notifications.buildSummaryNotification(account, notificationData, false); verify(builder, never()).addAction(R.drawable.notification_action_delete, "Delete", null); } private Builder createFakeNotificationBuilder() { Builder builder = mockBuilder(Builder.class); when(builder.build()).thenReturn(FAKE_NOTIFICATION); return builder; } private Account createFakeAccount() { Account account = mock(Account.class); when(account.getChipColor()).thenReturn(ACCOUNT_COLOR); when(account.getAccountNumber()).thenReturn(ACCOUNT_NUMBER); NotificationSetting notificationSetting = mock(NotificationSetting.class); when(account.getNotificationSetting()).thenReturn(notificationSetting); return account; } private NotificationData createFakeNotificationData(Account account) { NotificationData notificationData = mock(NotificationData.class); when(notificationData.getUnreadMessageCount()).thenReturn(UNREAD_MESSAGE_COUNT); when(notificationData.getNewMessagesCount()).thenReturn(NEW_MESSAGE_COUNT); when(notificationData.getAccount()).thenReturn(account); NotificationContent content = new NotificationContent(null, SENDER, SUBJECT, PREVIEW, SUMMARY, false); NotificationContent content2 = new NotificationContent(null, SENDER_2, SUBJECT_2, PREVIEW_2, SUMMARY_2, true); List<NotificationContent> contents = Arrays.asList(content, content2); when(notificationData.getContentForSummaryNotification()).thenReturn(contents); NotificationHolder holder = new NotificationHolder(NOTIFICATION_ID, content); when(notificationData.getHolderForLatestNotification()).thenReturn(holder); return notificationData; } private TestDeviceNotifications createDeviceNotifications(Builder builder, LockScreenNotification lockScreenNotification) { NotificationController controller = createFakeNotificationController(builder); NotificationActionCreator actionCreator = mock(NotificationActionCreator.class); WearNotifications wearNotifications = mock(WearNotifications.class); return new TestDeviceNotifications(controller, actionCreator, lockScreenNotification, wearNotifications); } private NotificationController createFakeNotificationController(final Builder builder) { Application context = RuntimeEnvironment.application; NotificationController controller = mock(NotificationController.class); when(controller.getContext()).thenReturn(context); when(controller.getAccountName(any(Account.class))).thenReturn(ACCOUNT_NAME); when(controller.createNotificationBuilder()).thenAnswer(new Answer<Builder>() { private int invocationCount = 0; @Override public Builder answer(InvocationOnMock invocation) throws Throwable { invocationCount++; switch (invocationCount) { case 1: { return builder; } case 2: { return builder2; } } throw new AssertionError("createNotificationBuilder() invoked more than twice"); } }); return controller; } static class TestDeviceNotifications extends DeviceNotifications { BigTextStyle bigTextStyle = mockBuilder(BigTextStyle.class); InboxStyle inboxStyle = mockBuilder(InboxStyle.class); TestDeviceNotifications(NotificationController controller, NotificationActionCreator actionCreator, LockScreenNotification lockScreenNotification, WearNotifications wearNotifications) { super(controller, actionCreator, lockScreenNotification, wearNotifications); } @Override protected BigTextStyle createBigTextStyle(Builder builder) { return bigTextStyle; } @Override protected InboxStyle createInboxStyle(Builder builder) { return inboxStyle; } } }