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 681175abd..a5f9583e7 100644 --- a/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -107,25 +107,6 @@ public class MessagingController implements Runnable { */ private static final String[] EMPTY_STRING_ARRAY = new String[0]; - /** - * The maximum message size that we'll consider to be "small". A small message is downloaded - * in full immediately instead of in pieces. Anything over this size will be downloaded in - * pieces with attachments being left off completely and downloaded on demand. - * - * - * 25k for a "small" message was picked by educated trial and error. - * http://answers.google.com/answers/threadview?id=312463 claims that the - * average size of an email is 59k, which I feel is too large for our - * blind download. The following tests were performed on a download of - * 25 random messages. - *
-     * 5k - 61 seconds,
-     * 25k - 51 seconds,
-     * 55k - 53 seconds,
-     * 
- * So 25k gives good performance and a reasonable data footprint. Sounds good to me. - */ - private static final String PENDING_COMMAND_MOVE_OR_COPY = "com.fsck.k9.MessagingController.moveOrCopy"; private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK = "com.fsck.k9.MessagingController.moveOrCopyBulk"; private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW = "com.fsck.k9.MessagingController.moveOrCopyBulkNew"; @@ -327,7 +308,6 @@ public class MessagingController implements Runnable { throw new Error(e); } - public void addListener(MessagingListener listener) { mListeners.add(listener); refreshListener(listener); @@ -438,74 +418,80 @@ public class MessagingController implements Runnable { put("doRefreshRemote", listener, new Runnable() { @Override public void run() { - List localFolders = null; - try { - Store store = account.getRemoteStore(); - - List remoteFolders = store.getPersonalNamespaces(false); - - LocalStore localStore = account.getLocalStore(); - Set remoteFolderNames = new HashSet(); - List foldersToCreate = new LinkedList(); - - localFolders = localStore.getPersonalNamespaces(false); - Set localFolderNames = new HashSet(); - for (Folder localFolder : localFolders) { - localFolderNames.add(localFolder.getName()); - } - for (Folder remoteFolder : remoteFolders) { - if (localFolderNames.contains(remoteFolder.getName()) == false) { - LocalFolder localFolder = localStore.getFolder(remoteFolder.getName()); - foldersToCreate.add(localFolder); - } - remoteFolderNames.add(remoteFolder.getName()); - } - localStore.createFolders(foldersToCreate, account.getDisplayCount()); - - localFolders = localStore.getPersonalNamespaces(false); - - /* - * Clear out any folders that are no longer on the remote store. - */ - for (Folder localFolder : localFolders) { - String localFolderName = localFolder.getName(); - - // FIXME: This is a hack used to clean up when we accidentally created the - // special placeholder folder "-NONE-". - if (K9.FOLDER_NONE.equals(localFolderName)) { - localFolder.delete(false); - } - - if (!account.isSpecialFolder(localFolderName) && - !remoteFolderNames.contains(localFolderName)) { - localFolder.delete(false); - } - } - - localFolders = localStore.getPersonalNamespaces(false); - - for (MessagingListener l : getListeners(listener)) { - l.listFolders(account, localFolders); - } - for (MessagingListener l : getListeners(listener)) { - l.listFoldersFinished(account); - } - } catch (Exception e) { - for (MessagingListener l : getListeners(listener)) { - l.listFoldersFailed(account, ""); - } - addErrorMessage(account, null, e); - } finally { - if (localFolders != null) { - for (Folder localFolder : localFolders) { - closeFolder(localFolder); - } - } - } + refreshRemoteSynchronous(account, listener); } }); } + @VisibleForTesting + void refreshRemoteSynchronous(final Account account, final MessagingListener listener) { + List localFolders = null; + try { + Store store = account.getRemoteStore(); + + List remoteFolders = store.getPersonalNamespaces(false); + + LocalStore localStore = account.getLocalStore(); + Set remoteFolderNames = new HashSet(); + List foldersToCreate = new LinkedList(); + + localFolders = localStore.getPersonalNamespaces(false); + Set localFolderNames = new HashSet(); + for (Folder localFolder : localFolders) { + localFolderNames.add(localFolder.getName()); + } + + for (Folder remoteFolder : remoteFolders) { + if (localFolderNames.contains(remoteFolder.getName()) == false) { + LocalFolder localFolder = localStore.getFolder(remoteFolder.getName()); + foldersToCreate.add(localFolder); + } + remoteFolderNames.add(remoteFolder.getName()); + } + localStore.createFolders(foldersToCreate, account.getDisplayCount()); + + localFolders = localStore.getPersonalNamespaces(false); + + /* + * Clear out any folders that are no longer on the remote store. + */ + for (Folder localFolder : localFolders) { + String localFolderName = localFolder.getName(); + + // FIXME: This is a hack used to clean up when we accidentally created the + // special placeholder folder "-NONE-". + if (K9.FOLDER_NONE.equals(localFolderName)) { + localFolder.delete(false); + } + + if (!account.isSpecialFolder(localFolderName) && + !remoteFolderNames.contains(localFolderName)) { + localFolder.delete(false); + } + } + + localFolders = localStore.getPersonalNamespaces(false); + + for (MessagingListener l : getListeners(listener)) { + l.listFolders(account, localFolders); + } + for (MessagingListener l : getListeners(listener)) { + l.listFoldersFinished(account); + } + } catch (Exception e) { + for (MessagingListener l : getListeners(listener)) { + l.listFoldersFailed(account, ""); + } + addErrorMessage(account, null, e); + } finally { + if (localFolders != null) { + for (Folder localFolder : localFolders) { + closeFolder(localFolder); + } + } + } + } + /** * Find all messages in any local account which match the query 'query' * @throws MessagingException diff --git a/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java b/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java index f5ee82817..1aeb522cf 100644 --- a/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java +++ b/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java @@ -1,15 +1,21 @@ package com.fsck.k9.controller; - +import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import android.content.Context; import com.fsck.k9.Account; import com.fsck.k9.AccountStats; +import com.fsck.k9.Preferences; import com.fsck.k9.mail.FetchProfile; +import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessageRetrievalListener; @@ -19,12 +25,15 @@ import com.fsck.k9.mailstore.LocalFolder; import com.fsck.k9.mailstore.LocalMessage; import com.fsck.k9.mailstore.LocalStore; import com.fsck.k9.notification.NotificationController; +import com.fsck.k9.search.LocalSearch; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; +import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; @@ -37,11 +46,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anySet; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -62,6 +76,8 @@ public class MessagingControllerTest { @Mock private MessagingListener listener; @Mock + private LocalSearch search; + @Mock private LocalFolder localFolder; @Mock private Folder remoteFolder; @@ -74,13 +90,34 @@ public class MessagingControllerTest { @Captor private ArgumentCaptor> messageListCaptor; @Captor + private ArgumentCaptor> localFolderListCaptor; + @Captor private ArgumentCaptor fetchProfileCaptor; + @Captor + private ArgumentCaptor> messageRetrievalListenerCaptor; + + private Context appContext; + private Set reqFlags; + private Set forbiddenFlags; + + private List remoteMessages; + @Mock + private Message remoteOldMessage; + @Mock + private Message remoteNewMessage1; + @Mock + private Message remoteNewMessage2; + @Mock + private LocalMessage localNewMessage1; + @Mock + private LocalMessage localNewMessage2; + private volatile boolean hasFetchedMessage = false; @Before public void setUp() throws MessagingException { MockitoAnnotations.initMocks(this); - Context appContext = ShadowApplication.getInstance().getApplicationContext(); + appContext = ShadowApplication.getInstance().getApplicationContext(); controller = new MessagingController(appContext, notificationController); @@ -93,6 +130,348 @@ public class MessagingControllerTest { controller.stop(); } + @Test + public void listFoldersSynchronous_shouldNotifyTheListenerListingStarted() throws MessagingException { + List folders = Collections.singletonList(localFolder); + when(localStore.getPersonalNamespaces(false)).thenReturn(folders); + + controller.listFoldersSynchronous(account, false, listener); + + verify(listener).listFoldersStarted(account); + } + + @Test + public void listFoldersSynchronous_shouldNotifyTheListenerOfTheListOfFolders() throws MessagingException { + List folders = Collections.singletonList(localFolder); + when(localStore.getPersonalNamespaces(false)).thenReturn(folders); + + controller.listFoldersSynchronous(account, false, listener); + + verify(listener).listFolders(eq(account), localFolderListCaptor.capture()); + assertEquals(folders, localFolderListCaptor.getValue()); + } + + @Test + public void listFoldersSynchronous_shouldNotifyFailureOnException() throws MessagingException { + when(localStore.getPersonalNamespaces(false)).thenThrow(new MessagingException("Test")); + + controller.listFoldersSynchronous(account, true, listener); + + verify(listener).listFoldersFailed(account, "Test"); + } + + @Test + public void listFoldersSynchronous_shouldNotNotifyFinishedAfterFailure() throws MessagingException { + when(localStore.getPersonalNamespaces(false)).thenThrow(new MessagingException("Test")); + + controller.listFoldersSynchronous(account, true, listener); + + verify(listener, never()).listFoldersFinished(account); + } + + @Test + public void listFoldersSynchronous_shouldNotifyFinishedAfterSuccess() throws MessagingException { + List folders = Collections.singletonList(localFolder); + when(localStore.getPersonalNamespaces(false)).thenReturn(folders); + + controller.listFoldersSynchronous(account, false, listener); + + verify(listener).listFoldersFinished(account); + } + + @Test + public void refreshRemoteSynchronous_shouldCreateFoldersFromRemote() throws MessagingException { + configureRemoteStoreWithFolder(); + LocalFolder newLocalFolder = mock(LocalFolder.class); + + List folders = Collections.singletonList(remoteFolder); + when(remoteStore.getPersonalNamespaces(false)).thenAnswer(createAnswer(folders)); + when(remoteFolder.getName()).thenReturn("NewFolder"); + when(localStore.getFolder("NewFolder")).thenReturn(newLocalFolder); + + controller.refreshRemoteSynchronous(account, listener); + + verify(localStore).createFolders(eq(Collections.singletonList(newLocalFolder)), anyInt()); + } + + @Test + public void refreshRemoteSynchronous_shouldDeleteFoldersNotOnRemote() throws MessagingException { + configureRemoteStoreWithFolder(); + LocalFolder oldLocalFolder = mock(LocalFolder.class); + when(oldLocalFolder.getName()).thenReturn("OldLocalFolder"); + when(localStore.getPersonalNamespaces(false)) + .thenReturn(Collections.singletonList(oldLocalFolder)); + List folders = Collections.emptyList(); + when(remoteStore.getPersonalNamespaces(false)).thenAnswer(createAnswer(folders)); + + controller.refreshRemoteSynchronous(account, listener); + + verify(oldLocalFolder).delete(false); + } + + @Test + public void refreshRemoteSynchronous_shouldNotDeleteFoldersOnRemote() throws MessagingException { + configureRemoteStoreWithFolder(); + when(localStore.getPersonalNamespaces(false)) + .thenReturn(Collections.singletonList(localFolder)); + List folders = Collections.singletonList(remoteFolder); + when(remoteStore.getPersonalNamespaces(false)).thenAnswer(createAnswer(folders)); + + controller.refreshRemoteSynchronous(account, listener); + + verify(localFolder, never()).delete(false); + } + + @Test + public void refreshRemoteSynchronous_shouldNotDeleteSpecialFoldersNotOnRemote() throws MessagingException { + configureRemoteStoreWithFolder(); + LocalFolder missingSpecialFolder = mock(LocalFolder.class); + when(account.isSpecialFolder("Outbox")).thenReturn(true); + when(missingSpecialFolder.getName()).thenReturn("Outbox"); + when(localStore.getPersonalNamespaces(false)) + .thenReturn(Collections.singletonList(missingSpecialFolder)); + List folders = Collections.emptyList(); + when(remoteStore.getPersonalNamespaces(false)).thenAnswer(createAnswer(folders)); + + controller.refreshRemoteSynchronous(account, listener); + + verify(missingSpecialFolder, never()).delete(false); + } + + public static Answer createAnswer(final T value) { + return new Answer() { + @Override + public T answer(InvocationOnMock invocation) throws Throwable { + return value; + } + }; + } + + @Test + public void refreshRemoteSynchronous_shouldProvideFolderList() throws MessagingException { + configureRemoteStoreWithFolder(); + List folders = Collections.singletonList(localFolder); + when(localStore.getPersonalNamespaces(false)).thenReturn(folders); + + controller.refreshRemoteSynchronous(account, listener); + + verify(listener).listFolders(account, folders); + } + + @Test + public void refreshRemoteSynchronous_shouldNotifyFinishedAfterSuccess() throws MessagingException { + configureRemoteStoreWithFolder(); + List folders = Collections.singletonList(localFolder); + when(localStore.getPersonalNamespaces(false)).thenReturn(folders); + + controller.refreshRemoteSynchronous(account, listener); + + verify(listener).listFoldersFinished(account); + } + + @Test + public void refreshRemoteSynchronous_shouldNotNotifyFinishedAfterFailure() throws MessagingException { + configureRemoteStoreWithFolder(); + when(localStore.getPersonalNamespaces(false)).thenThrow(new MessagingException("Test")); + + controller.refreshRemoteSynchronous(account, listener); + + verify(listener, never()).listFoldersFinished(account); + } + + @Test + public void searchLocalMessagesSynchronous_shouldNotifyStartedListingLocalMessages() + throws Exception { + setAccountsInPreferences(Collections.singletonMap("1", account)); + when(search.getAccountUuids()).thenReturn(new String[]{"allAccounts"}); + + controller.searchLocalMessagesSynchronous(search, listener); + + verify(listener).listLocalMessagesStarted(account, null); + } + + @Test + public void searchLocalMessagesSynchronous_shouldCallSearchForMessagesOnLocalStore() + throws Exception { + setAccountsInPreferences(Collections.singletonMap("1", account)); + when(search.getAccountUuids()).thenReturn(new String[]{"allAccounts"}); + + controller.searchLocalMessagesSynchronous(search, listener); + + verify(localStore).searchForMessages(any(MessageRetrievalListener.class), eq(search)); + } + + @Test + public void searchLocalMessagesSynchronous_shouldNotifyFailureIfStoreThrowsException() throws Exception { + setAccountsInPreferences(Collections.singletonMap("1", account)); + when(search.getAccountUuids()).thenReturn(new String[]{"allAccounts"}); + when(localStore.searchForMessages(any(MessageRetrievalListener.class), eq(search))) + .thenThrow(new MessagingException("Test")); + + controller.searchLocalMessagesSynchronous(search, listener); + + verify(listener).listLocalMessagesFailed(account, null, "Test"); + } + + @Test + public void searchLocalMessagesSynchronous_shouldNotifyWhenStoreFinishesRetrievingAMessage() + throws Exception { + setAccountsInPreferences(Collections.singletonMap("1", account)); + LocalMessage localMessage = mock(LocalMessage.class); + when(localMessage.getFolder()).thenReturn(localFolder); + when(search.getAccountUuids()).thenReturn(new String[]{"allAccounts"}); + when(localStore.searchForMessages(any(MessageRetrievalListener.class), eq(search))) + .thenThrow(new MessagingException("Test")); + + controller.searchLocalMessagesSynchronous(search, listener); + + verify(localStore).searchForMessages(messageRetrievalListenerCaptor.capture(), eq(search)); + messageRetrievalListenerCaptor.getValue().messageFinished(localMessage, 1, 1); + verify(listener).listLocalMessagesAddMessages(eq(account), + eq((String) null), eq(Collections.singletonList(localMessage))); + } + + private void setupRemoteSearch() throws Exception { + setAccountsInPreferences(Collections.singletonMap("1", account)); + configureRemoteStoreWithFolder(); + + remoteMessages = new ArrayList<>(); + Collections.addAll(remoteMessages, remoteOldMessage, remoteNewMessage1, remoteNewMessage2); + List newRemoteMessages = new ArrayList<>(); + Collections.addAll(newRemoteMessages, remoteNewMessage1, remoteNewMessage2); + + when(remoteOldMessage.getUid()).thenReturn("oldMessageUid"); + when(remoteNewMessage1.getUid()).thenReturn("newMessageUid1"); + when(localNewMessage1.getUid()).thenReturn("newMessageUid1"); + when(remoteNewMessage2.getUid()).thenReturn("newMessageUid2"); + when(localNewMessage2.getUid()).thenReturn("newMessageUid2"); + when(remoteFolder.search(anyString(), anySet(), anySet())).thenReturn(remoteMessages); + when(localFolder.extractNewMessages(Matchers.>any())).thenReturn(newRemoteMessages); + when(localFolder.getMessage("newMessageUid1")).thenReturn(localNewMessage1); + when(localFolder.getMessage("newMessageUid2")).thenAnswer( + new Answer() { + @Override + public LocalMessage answer(InvocationOnMock invocation) throws Throwable { + if(hasFetchedMessage) { + return localNewMessage2; + } + else + return null; + } + } + ); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + hasFetchedMessage = true; + return null; + } + }).when(remoteFolder).fetch( + Matchers.>eq(Collections.singletonList(remoteNewMessage2)), + any(FetchProfile.class), + Matchers.eq(null)); + reqFlags = Collections.singleton(Flag.ANSWERED); + forbiddenFlags = Collections.singleton(Flag.DELETED); + + when(account.getRemoteSearchNumResults()).thenReturn(50); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldNotifyStartedListingRemoteMessages() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(listener).remoteSearchStarted(FOLDER_NAME); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldQueryRemoteFolder() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(remoteFolder).search("query", reqFlags, forbiddenFlags); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldAskLocalFolderToDetermineNewMessages() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(localFolder).extractNewMessages(remoteMessages); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldTryAndGetNewMessages() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(localFolder).getMessage("newMessageUid1"); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldNotTryAndGetOldMessages() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(localFolder, never()).getMessage("oldMessageUid"); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldFetchNewMessages() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(remoteFolder, times(2)).fetch(eq(Collections.singletonList(remoteNewMessage2)), + fetchProfileCaptor.capture(), Matchers.eq(null)); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldNotFetchExistingMessages() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(remoteFolder, never()).fetch(eq(Collections.singletonList(remoteNewMessage1)), + fetchProfileCaptor.capture(), Matchers.eq(null)); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldNotifyListenerOfNewMessages() throws Exception { + setupRemoteSearch(); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(listener).remoteSearchAddMessage(FOLDER_NAME, localNewMessage1, 1, 2); + verify(listener).remoteSearchAddMessage(FOLDER_NAME, localNewMessage2, 2, 2); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldNotifyOnFailure() throws Exception { + setupRemoteSearch(); + when(account.getRemoteStore()).thenThrow(new MessagingException("Test")); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(listener).remoteSearchFailed(null, "Test"); + } + + @Test + public void searchRemoteMessagesSynchronous_shouldNotifyOnFinish() throws Exception { + setupRemoteSearch(); + when(account.getRemoteStore()).thenThrow(new MessagingException("Test")); + + controller.searchRemoteMessagesSynchronous("1", FOLDER_NAME, "query", reqFlags, forbiddenFlags, listener); + + verify(listener).remoteSearchFinished(FOLDER_NAME, 0, 50, Collections.emptyList()); + } + + @Test public void synchronizeMailboxSynchronous_withOneMessageInRemoteFolder_shouldFinishWithoutError() throws Exception { @@ -372,6 +751,7 @@ public class MessagingControllerTest { } private void configureAccount() throws MessagingException { + when(account.isAvailable(appContext)).thenReturn(true); when(account.getLocalStore()).thenReturn(localStore); when(account.getStats(any(Context.class))).thenReturn(accountStats); when(account.getMaximumAutoDownloadMessageSize()).thenReturn(MAXIMUM_SMALL_MESSAGE_SIZE); @@ -379,10 +759,25 @@ public class MessagingControllerTest { private void configureLocalStore() { when(localStore.getFolder(FOLDER_NAME)).thenReturn(localFolder); + when(localFolder.getName()).thenReturn(FOLDER_NAME); } private void configureRemoteStoreWithFolder() throws MessagingException { when(account.getRemoteStore()).thenReturn(remoteStore); when(remoteStore.getFolder(FOLDER_NAME)).thenReturn(remoteFolder); + when(remoteFolder.getName()).thenReturn(FOLDER_NAME); + } + + private void setAccountsInPreferences(Map newAccounts) + throws Exception { + Field accounts = Preferences.class.getDeclaredField("accounts"); + accounts.setAccessible(true); + accounts.set(Preferences.getPreferences(appContext), newAccounts); + + Field accountsInOrder = Preferences.class.getDeclaredField("accountsInOrder"); + accountsInOrder.setAccessible(true); + ArrayList newAccountsInOrder = new ArrayList<>(); + newAccountsInOrder.addAll(newAccounts.values()); + accountsInOrder.set(Preferences.getPreferences(appContext), newAccountsInOrder); } }