Search in sources :

Example 1 with AccountStats

use of com.fsck.k9.AccountStats in project k-9 by k9mail.

the class MessagingController method searchLocalMessagesSynchronous.

@VisibleForTesting
void searchLocalMessagesSynchronous(final LocalSearch search, final MessagingListener listener) {
    final AccountStats stats = new AccountStats();
    final Set<String> uuidSet = new HashSet<>(Arrays.asList(search.getAccountUuids()));
    List<Account> accounts = Preferences.getPreferences(context).getAccounts();
    boolean allAccounts = uuidSet.contains(SearchSpecification.ALL_ACCOUNTS);
    // for every account we want to search do the query in the localstore
    for (final Account account : accounts) {
        if (!allAccounts && !uuidSet.contains(account.getUuid())) {
            continue;
        }
        // Collecting statistics of the search result
        MessageRetrievalListener<LocalMessage> retrievalListener = new MessageRetrievalListener<LocalMessage>() {

            @Override
            public void messageStarted(String message, int number, int ofTotal) {
            }

            @Override
            public void messagesFinished(int number) {
            }

            @Override
            public void messageFinished(LocalMessage message, int number, int ofTotal) {
                if (!isMessageSuppressed(message)) {
                    List<LocalMessage> messages = new ArrayList<>();
                    messages.add(message);
                    stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0;
                    stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
                    if (listener != null) {
                        listener.listLocalMessagesAddMessages(account, null, messages);
                    }
                }
            }
        };
        // build and do the query in the localstore
        try {
            LocalStore localStore = account.getLocalStore();
            localStore.searchForMessages(retrievalListener, search);
        } catch (Exception e) {
            addErrorMessage(account, null, e);
        }
    }
    // publish the total search statistics
    if (listener != null) {
        listener.searchStats(stats);
    }
}
Also used : SearchAccount(com.fsck.k9.search.SearchAccount) Account(com.fsck.k9.Account) LocalMessage(com.fsck.k9.mailstore.LocalMessage) ArrayList(java.util.ArrayList) LocalStore(com.fsck.k9.mailstore.LocalStore) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) UnavailableStorageException(com.fsck.k9.mailstore.UnavailableStorageException) IOException(java.io.IOException) MessagingException(com.fsck.k9.mail.MessagingException) AuthenticationFailedException(com.fsck.k9.mail.AuthenticationFailedException) MessageRetrievalListener(com.fsck.k9.mail.MessageRetrievalListener) AccountStats(com.fsck.k9.AccountStats) HashSet(java.util.HashSet) VisibleForTesting(android.support.annotation.VisibleForTesting)

Example 2 with AccountStats

use of com.fsck.k9.AccountStats in project k-9 by k9mail.

the class MessagingController method downloadMessages.

/**
     * Fetches the messages described by inputMessages from the remote store and writes them to
     * local storage.
     *
     * @param account
     *         The account the remote store belongs to.
     * @param remoteFolder
     *         The remote folder to download messages from.
     * @param localFolder
     *         The {@link LocalFolder} instance corresponding to the remote folder.
     * @param inputMessages
     *         A list of messages objects that store the UIDs of which messages to download.
     * @param flagSyncOnly
     *         Only flags will be fetched from the remote store if this is {@code true}.
     * @param purgeToVisibleLimit
     *         If true, local messages will be purged down to the limit of visible messages.
     *
     * @return The number of downloaded messages that are not flagged as {@link Flag#SEEN}.
     *
     * @throws MessagingException
     */
private int downloadMessages(final Account account, final Folder remoteFolder, final LocalFolder localFolder, List<Message> inputMessages, boolean flagSyncOnly, boolean purgeToVisibleLimit) throws MessagingException {
    final Date earliestDate = account.getEarliestPollDate();
    // now
    Date downloadStarted = new Date();
    if (earliestDate != null) {
        Timber.d("Only syncing messages after %s", earliestDate);
    }
    final String folder = remoteFolder.getName();
    int unreadBeforeStart = 0;
    try {
        AccountStats stats = account.getStats(context);
        unreadBeforeStart = stats.unreadMessageCount;
    } catch (MessagingException e) {
        Timber.e(e, "Unable to getUnreadMessageCount for account: %s", account);
    }
    List<Message> syncFlagMessages = new ArrayList<>();
    List<Message> unsyncedMessages = new ArrayList<>();
    final AtomicInteger newMessages = new AtomicInteger(0);
    List<Message> messages = new ArrayList<>(inputMessages);
    for (Message message : messages) {
        evaluateMessageForDownload(message, folder, localFolder, remoteFolder, account, unsyncedMessages, syncFlagMessages, flagSyncOnly);
    }
    final AtomicInteger progress = new AtomicInteger(0);
    final int todo = unsyncedMessages.size() + syncFlagMessages.size();
    for (MessagingListener l : getListeners()) {
        l.synchronizeMailboxProgress(account, folder, progress.get(), todo);
    }
    Timber.d("SYNC: Have %d unsynced messages", unsyncedMessages.size());
    messages.clear();
    final List<Message> largeMessages = new ArrayList<>();
    final List<Message> smallMessages = new ArrayList<>();
    if (!unsyncedMessages.isEmpty()) {
        /*
             * Reverse the order of the messages. Depending on the server this may get us
             * fetch results for newest to oldest. If not, no harm done.
             */
        Collections.sort(unsyncedMessages, new UidReverseComparator());
        int visibleLimit = localFolder.getVisibleLimit();
        int listSize = unsyncedMessages.size();
        if ((visibleLimit > 0) && (listSize > visibleLimit)) {
            unsyncedMessages = unsyncedMessages.subList(0, visibleLimit);
        }
        FetchProfile fp = new FetchProfile();
        if (remoteFolder.supportsFetchingFlags()) {
            fp.add(FetchProfile.Item.FLAGS);
        }
        fp.add(FetchProfile.Item.ENVELOPE);
        Timber.d("SYNC: About to fetch %d unsynced messages for folder %s", unsyncedMessages.size(), folder);
        fetchUnsyncedMessages(account, remoteFolder, unsyncedMessages, smallMessages, largeMessages, progress, todo, fp);
        String updatedPushState = localFolder.getPushState();
        for (Message message : unsyncedMessages) {
            String newPushState = remoteFolder.getNewPushState(updatedPushState, message);
            if (newPushState != null) {
                updatedPushState = newPushState;
            }
        }
        localFolder.setPushState(updatedPushState);
        Timber.d("SYNC: Synced unsynced messages for folder %s", folder);
    }
    Timber.d("SYNC: Have %d large messages and %d small messages out of %d unsynced messages", largeMessages.size(), smallMessages.size(), unsyncedMessages.size());
    unsyncedMessages.clear();
    /*
         * Grab the content of the small messages first. This is going to
         * be very fast and at very worst will be a single up of a few bytes and a single
         * download of 625k.
         */
    FetchProfile fp = new FetchProfile();
    //TODO: Only fetch small and large messages if we have some
    fp.add(FetchProfile.Item.BODY);
    //        fp.add(FetchProfile.Item.FLAGS);
    //        fp.add(FetchProfile.Item.ENVELOPE);
    downloadSmallMessages(account, remoteFolder, localFolder, smallMessages, progress, unreadBeforeStart, newMessages, todo, fp);
    smallMessages.clear();
    /*
         * Now do the large messages that require more round trips.
         */
    fp = new FetchProfile();
    fp.add(FetchProfile.Item.STRUCTURE);
    downloadLargeMessages(account, remoteFolder, localFolder, largeMessages, progress, unreadBeforeStart, newMessages, todo, fp);
    largeMessages.clear();
    /*
         * Refresh the flags for any messages in the local store that we didn't just
         * download.
         */
    refreshLocalMessageFlags(account, remoteFolder, localFolder, syncFlagMessages, progress, todo);
    Timber.d("SYNC: Synced remote messages for folder %s, %d new messages", folder, newMessages.get());
    if (purgeToVisibleLimit) {
        localFolder.purgeToVisibleLimit(new MessageRemovalListener() {

            @Override
            public void messageRemoved(Message message) {
                for (MessagingListener l : getListeners()) {
                    l.synchronizeMailboxRemovedMessage(account, folder, message);
                }
            }
        });
    }
    // If the oldest message seen on this sync is newer than
    // the oldest message seen on the previous sync, then
    // we want to move our high-water mark forward
    // this is all here just for pop which only syncs inbox
    // this would be a little wrong for IMAP (we'd want a folder-level pref, not an account level pref.)
    // fortunately, we just don't care.
    Long oldestMessageTime = localFolder.getOldestMessageDate();
    if (oldestMessageTime != null) {
        Date oldestExtantMessage = new Date(oldestMessageTime);
        if (oldestExtantMessage.before(downloadStarted) && oldestExtantMessage.after(new Date(account.getLatestOldMessageSeenTime()))) {
            account.setLatestOldMessageSeenTime(oldestExtantMessage.getTime());
            account.save(Preferences.getPreferences(context));
        }
    }
    return newMessages.get();
}
Also used : FetchProfile(com.fsck.k9.mail.FetchProfile) LocalMessage(com.fsck.k9.mailstore.LocalMessage) MimeMessage(com.fsck.k9.mail.internet.MimeMessage) Message(com.fsck.k9.mail.Message) MessagingException(com.fsck.k9.mail.MessagingException) ArrayList(java.util.ArrayList) Date(java.util.Date) SuppressLint(android.annotation.SuppressLint) MessageRemovalListener(com.fsck.k9.mailstore.MessageRemovalListener) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AccountStats(com.fsck.k9.AccountStats)

Example 3 with AccountStats

use of com.fsck.k9.AccountStats in project k-9 by k9mail.

the class UnreadWidgetProvider method updateWidget.

public static void updateWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, String accountUuid) {
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.unread_widget_layout);
    int unreadCount = 0;
    String accountName = context.getString(R.string.app_name);
    Intent clickIntent = null;
    try {
        BaseAccount account = null;
        AccountStats stats = null;
        SearchAccount searchAccount = null;
        if (SearchAccount.UNIFIED_INBOX.equals(accountUuid)) {
            searchAccount = SearchAccount.createUnifiedInboxAccount(context);
        } else if (SearchAccount.ALL_MESSAGES.equals(accountUuid)) {
            searchAccount = SearchAccount.createAllMessagesAccount(context);
        }
        if (searchAccount != null) {
            account = searchAccount;
            MessagingController controller = MessagingController.getInstance(context);
            stats = controller.getSearchAccountStatsSynchronous(searchAccount, null);
            clickIntent = MessageList.intentDisplaySearch(context, searchAccount.getRelatedSearch(), false, true, true);
        } else {
            Account realAccount = Preferences.getPreferences(context).getAccount(accountUuid);
            if (realAccount != null) {
                account = realAccount;
                stats = realAccount.getStats(context);
                if (K9.FOLDER_NONE.equals(realAccount.getAutoExpandFolderName())) {
                    clickIntent = FolderList.actionHandleAccountIntent(context, realAccount, false);
                } else {
                    LocalSearch search = new LocalSearch(realAccount.getAutoExpandFolderName());
                    search.addAllowedFolder(realAccount.getAutoExpandFolderName());
                    search.addAccountUuid(account.getUuid());
                    clickIntent = MessageList.intentDisplaySearch(context, search, false, true, true);
                }
                clickIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
            }
        }
        if (account != null) {
            accountName = account.getDescription();
        }
        if (stats != null) {
            unreadCount = stats.unreadMessageCount;
        }
    } catch (Exception e) {
        Timber.e(e, "Error getting widget configuration");
    }
    if (unreadCount <= 0) {
        // Hide TextView for unread count if there are no unread messages.
        remoteViews.setViewVisibility(R.id.unread_count, View.GONE);
    } else {
        remoteViews.setViewVisibility(R.id.unread_count, View.VISIBLE);
        String displayCount = (unreadCount <= MAX_COUNT) ? String.valueOf(unreadCount) : String.valueOf(MAX_COUNT) + "+";
        remoteViews.setTextViewText(R.id.unread_count, displayCount);
    }
    remoteViews.setTextViewText(R.id.account_name, accountName);
    if (clickIntent == null) {
        // If the widget configuration couldn't be loaded we open the configuration
        // activity when the user clicks the widget.
        clickIntent = new Intent(context, UnreadWidgetConfiguration.class);
        clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    }
    clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, clickIntent, 0);
    remoteViews.setOnClickPendingIntent(R.id.unread_widget_layout, pendingIntent);
    appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
Also used : SearchAccount(com.fsck.k9.search.SearchAccount) Account(com.fsck.k9.Account) BaseAccount(com.fsck.k9.BaseAccount) UnreadWidgetConfiguration(com.fsck.k9.activity.UnreadWidgetConfiguration) MessagingController(com.fsck.k9.controller.MessagingController) Intent(android.content.Intent) PendingIntent(android.app.PendingIntent) SearchAccount(com.fsck.k9.search.SearchAccount) RemoteViews(android.widget.RemoteViews) LocalSearch(com.fsck.k9.search.LocalSearch) BaseAccount(com.fsck.k9.BaseAccount) PendingIntent(android.app.PendingIntent) AccountStats(com.fsck.k9.AccountStats)

Example 4 with AccountStats

use of com.fsck.k9.AccountStats in project k-9 by k9mail.

the class Account method getStats.

/**
     * @return <code>null</code> if not available
     * @throws MessagingException
     * @see {@link #isAvailable(Context)}
     */
public AccountStats getStats(Context context) throws MessagingException {
    if (!isAvailable(context)) {
        return null;
    }
    AccountStats stats = new AccountStats();
    ContentResolver cr = context.getContentResolver();
    Uri uri = Uri.withAppendedPath(EmailProvider.CONTENT_URI, "account/" + getUuid() + "/stats");
    String[] projection = { StatsColumns.UNREAD_COUNT, StatsColumns.FLAGGED_COUNT };
    // Create LocalSearch instance to exclude special folders (Trash, Drafts, Spam, Outbox,
    // Sent) and limit the search to displayable folders.
    LocalSearch search = new LocalSearch();
    excludeSpecialFolders(search);
    limitToDisplayableFolders(search);
    // Use the LocalSearch instance to create a WHERE clause to query the content provider
    StringBuilder query = new StringBuilder();
    List<String> queryArgs = new ArrayList<>();
    ConditionsTreeNode conditions = search.getConditions();
    SqlQueryBuilder.buildWhereClause(this, conditions, query, queryArgs);
    String selection = query.toString();
    String[] selectionArgs = queryArgs.toArray(new String[0]);
    Cursor cursor = cr.query(uri, projection, selection, selectionArgs, null);
    try {
        if (cursor != null && cursor.moveToFirst()) {
            stats.unreadMessageCount = cursor.getInt(0);
            stats.flaggedMessageCount = cursor.getInt(1);
        }
    } finally {
        Utility.closeQuietly(cursor);
    }
    LocalStore localStore = getLocalStore();
    if (K9.measureAccounts()) {
        stats.size = localStore.getSize();
    }
    return stats;
}
Also used : ConditionsTreeNode(com.fsck.k9.search.ConditionsTreeNode) LocalSearch(com.fsck.k9.search.LocalSearch) ArrayList(java.util.ArrayList) LocalStore(com.fsck.k9.mailstore.LocalStore) Cursor(android.database.Cursor) Uri(android.net.Uri) ContentResolver(android.content.ContentResolver)

Example 5 with AccountStats

use of com.fsck.k9.AccountStats in project k-9 by k9mail.

the class MessagingController method checkMailForAccount.

private void checkMailForAccount(final Context context, final Account account, final boolean ignoreLastCheckedTime, final MessagingListener listener) {
    if (!account.isAvailable(context)) {
        Timber.i("Skipping synchronizing unavailable account %s", account.getDescription());
        return;
    }
    final long accountInterval = account.getAutomaticCheckIntervalMinutes() * 60 * 1000;
    if (!ignoreLastCheckedTime && accountInterval <= 0) {
        Timber.i("Skipping synchronizing account %s", account.getDescription());
        return;
    }
    Timber.i("Synchronizing account %s", account.getDescription());
    account.setRingNotified(false);
    sendPendingMessages(account, listener);
    try {
        Account.FolderMode aDisplayMode = account.getFolderDisplayMode();
        Account.FolderMode aSyncMode = account.getFolderSyncMode();
        Store localStore = account.getLocalStore();
        for (final Folder folder : localStore.getPersonalNamespaces(false)) {
            folder.open(Folder.OPEN_MODE_RW);
            Folder.FolderClass fDisplayClass = folder.getDisplayClass();
            Folder.FolderClass fSyncClass = folder.getSyncClass();
            if (modeMismatch(aDisplayMode, fDisplayClass)) {
                continue;
            }
            if (modeMismatch(aSyncMode, fSyncClass)) {
                continue;
            }
            synchronizeFolder(account, folder, ignoreLastCheckedTime, accountInterval, listener);
        }
    } catch (MessagingException e) {
        Timber.e(e, "Unable to synchronize account %s", account.getName());
        addErrorMessage(account, null, e);
    } finally {
        putBackground("clear notification flag for " + account.getDescription(), null, new Runnable() {

            @Override
            public void run() {
                Timber.v("Clearing notification flag for %s", account.getDescription());
                account.setRingNotified(false);
                try {
                    AccountStats stats = account.getStats(context);
                    if (stats == null || stats.unreadMessageCount == 0) {
                        notificationController.clearNewMailNotifications(account);
                    }
                } catch (MessagingException e) {
                    Timber.e(e, "Unable to getUnreadMessageCount for account: %s", account);
                }
            }
        });
    }
}
Also used : SearchAccount(com.fsck.k9.search.SearchAccount) Account(com.fsck.k9.Account) MessagingException(com.fsck.k9.mail.MessagingException) LocalStore(com.fsck.k9.mailstore.LocalStore) Store(com.fsck.k9.mail.Store) Pop3Store(com.fsck.k9.mail.store.pop3.Pop3Store) Folder(com.fsck.k9.mail.Folder) LocalFolder(com.fsck.k9.mailstore.LocalFolder) AccountStats(com.fsck.k9.AccountStats)

Aggregations

AccountStats (com.fsck.k9.AccountStats)5 Account (com.fsck.k9.Account)4 SearchAccount (com.fsck.k9.search.SearchAccount)4 ArrayList (java.util.ArrayList)4 MessagingException (com.fsck.k9.mail.MessagingException)3 LocalStore (com.fsck.k9.mailstore.LocalStore)3 LocalSearch (com.fsck.k9.search.LocalSearch)3 SuppressLint (android.annotation.SuppressLint)2 ContentResolver (android.content.ContentResolver)2 Cursor (android.database.Cursor)2 Uri (android.net.Uri)2 LocalMessage (com.fsck.k9.mailstore.LocalMessage)2 ConditionsTreeNode (com.fsck.k9.search.ConditionsTreeNode)2 PendingIntent (android.app.PendingIntent)1 Intent (android.content.Intent)1 VisibleForTesting (android.support.annotation.VisibleForTesting)1 RemoteViews (android.widget.RemoteViews)1 BaseAccount (com.fsck.k9.BaseAccount)1 Preferences (com.fsck.k9.Preferences)1 UnreadWidgetConfiguration (com.fsck.k9.activity.UnreadWidgetConfiguration)1