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);
}
}
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();
}
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);
}
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;
}
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);
}
}
});
}
}
Aggregations