Merge pull request #3249 from k9mail/shrink_EmailProvider
Move some code out of EmailProvider
This commit is contained in:
commit
4678e467a6
11 changed files with 163 additions and 296 deletions
|
@ -1,6 +1,7 @@
|
|||
|
||||
package com.fsck.k9;
|
||||
|
||||
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
|
@ -8,44 +9,39 @@ import java.util.Arrays;
|
|||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import timber.log.Timber;
|
||||
|
||||
import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Folder.FolderClass;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.NetworkType;
|
||||
import com.fsck.k9.mail.Folder.FolderClass;
|
||||
import com.fsck.k9.mail.filter.Base64;
|
||||
import com.fsck.k9.mail.ssl.LocalKeyStore;
|
||||
import com.fsck.k9.mail.store.RemoteStore;
|
||||
import com.fsck.k9.mail.store.StoreConfig;
|
||||
import com.fsck.k9.mailstore.LocalStore;
|
||||
import com.fsck.k9.mailstore.StorageManager;
|
||||
import com.fsck.k9.mailstore.StorageManager.StorageProvider;
|
||||
import com.fsck.k9.mailstore.LocalStore;
|
||||
import com.fsck.k9.preferences.StorageEditor;
|
||||
import com.fsck.k9.preferences.Storage;
|
||||
import com.fsck.k9.provider.EmailProvider;
|
||||
import com.fsck.k9.provider.EmailProvider.StatsColumns;
|
||||
import com.fsck.k9.preferences.StorageEditor;
|
||||
import com.fsck.k9.search.ConditionsTreeNode;
|
||||
import com.fsck.k9.search.LocalSearch;
|
||||
import com.fsck.k9.search.SqlQueryBuilder;
|
||||
import com.fsck.k9.search.SearchSpecification.Attribute;
|
||||
import com.fsck.k9.search.SearchSpecification.SearchCondition;
|
||||
import com.fsck.k9.search.SearchSpecification.SearchField;
|
||||
import com.fsck.k9.mail.ssl.LocalKeyStore;
|
||||
import com.fsck.k9.view.ColorChip;
|
||||
import com.larswerkman.colorpicker.ColorPicker;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static com.fsck.k9.Preferences.getEnumStringPref;
|
||||
|
||||
|
@ -766,106 +762,6 @@ public class Account implements BaseAccount, StoreConfig {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
public int getFolderUnreadCount(Context context, String folderServerId) throws MessagingException {
|
||||
if (!isAvailable(context)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unreadMessageCount = 0;
|
||||
|
||||
Cursor cursor = loadUnreadCountForFolder(context, folderServerId);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
unreadMessageCount = cursor.getInt(0);
|
||||
}
|
||||
} finally {
|
||||
Utility.closeQuietly(cursor);
|
||||
}
|
||||
|
||||
return unreadMessageCount;
|
||||
}
|
||||
|
||||
private Cursor loadUnreadCountForFolder(Context context, String folderServerId) {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
|
||||
Uri uri = Uri.withAppendedPath(EmailProvider.CONTENT_URI,
|
||||
"account/" + getUuid() + "/stats");
|
||||
|
||||
String[] projection = {
|
||||
StatsColumns.UNREAD_COUNT,
|
||||
};
|
||||
|
||||
LocalSearch search = new LocalSearch();
|
||||
search.addAllowedFolder(folderServerId);
|
||||
|
||||
// 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[queryArgs.size()]);
|
||||
|
||||
return cr.query(uri, projection, selection, selectionArgs, null);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void setChipColor(int color) {
|
||||
chipColor = color;
|
||||
cacheChips();
|
||||
|
|
|
@ -115,6 +115,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
|||
private static final int DIALOG_RECREATE_ACCOUNT = 3;
|
||||
private static final int DIALOG_NO_FILE_MANAGER = 4;
|
||||
|
||||
private MessagingController controller;
|
||||
|
||||
/*
|
||||
* Must be serializable hence implementation class used for declaration.
|
||||
*/
|
||||
|
@ -246,7 +248,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
|||
@Override
|
||||
public void folderStatusChanged(Account account, String folderServerId, int unreadMessageCount) {
|
||||
try {
|
||||
AccountStats stats = account.getStats(Accounts.this);
|
||||
AccountStats stats = controller.getAccountStats(account);
|
||||
if (stats == null) {
|
||||
Timber.w("Unable to get account stats");
|
||||
} else {
|
||||
|
@ -365,6 +367,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
|||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
controller = MessagingController.getInstance(getApplicationContext());
|
||||
|
||||
if (!K9.isHideSpecialAccounts()) {
|
||||
createSpecialAccounts();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package com.fsck.k9.controller
|
||||
|
||||
import android.content.Context
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.AccountStats
|
||||
import com.fsck.k9.K9
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.mail.MessagingException
|
||||
import com.fsck.k9.search.LocalSearch
|
||||
import com.fsck.k9.search.SearchAccount
|
||||
|
||||
interface AccountStatsCollector {
|
||||
@Throws(MessagingException::class)
|
||||
fun getStats(account: Account): AccountStats?
|
||||
|
||||
fun getSearchAccountStats(searchAccount: SearchAccount): AccountStats
|
||||
}
|
||||
|
||||
internal class DefaultAccountStatsCollector(private val context: Context) : AccountStatsCollector {
|
||||
private val preferences = Preferences.getPreferences(context)
|
||||
|
||||
|
||||
override fun getStats(account: Account): AccountStats? {
|
||||
if (!account.isAvailable(context)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val localStore = account.localStore
|
||||
|
||||
val search = LocalSearch()
|
||||
account.excludeSpecialFolders(search)
|
||||
account.limitToDisplayableFolders(search)
|
||||
|
||||
val accountStats = localStore.getAccountStats(search)
|
||||
if (K9.measureAccounts()) {
|
||||
accountStats.size = localStore.size
|
||||
}
|
||||
|
||||
return accountStats
|
||||
}
|
||||
|
||||
override fun getSearchAccountStats(searchAccount: SearchAccount): AccountStats {
|
||||
val search = searchAccount.relatedSearch
|
||||
val accounts = getAccountsFromLocalSearch(search)
|
||||
|
||||
val aggregatedAccountStats = AccountStats()
|
||||
for (account in accounts) {
|
||||
val accountStats = account.localStore.getAccountStats(search)
|
||||
aggregatedAccountStats.unreadMessageCount += accountStats.unreadMessageCount
|
||||
aggregatedAccountStats.flaggedMessageCount += accountStats.flaggedMessageCount
|
||||
}
|
||||
|
||||
return aggregatedAccountStats
|
||||
}
|
||||
|
||||
private fun getAccountsFromLocalSearch(search: LocalSearch): List<Account> {
|
||||
return if (search.searchAllAccounts()) {
|
||||
preferences.accounts
|
||||
} else {
|
||||
preferences.accounts.filter { it.uuid in search.accountUuids }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,11 +27,8 @@ import java.util.concurrent.PriorityBlockingQueue;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
|
@ -93,13 +90,9 @@ import com.fsck.k9.mailstore.LocalStore;
|
|||
import com.fsck.k9.mailstore.MessageRemovalListener;
|
||||
import com.fsck.k9.mailstore.UnavailableStorageException;
|
||||
import com.fsck.k9.notification.NotificationController;
|
||||
import com.fsck.k9.provider.EmailProvider;
|
||||
import com.fsck.k9.provider.EmailProvider.StatsColumns;
|
||||
import com.fsck.k9.search.ConditionsTreeNode;
|
||||
import com.fsck.k9.search.LocalSearch;
|
||||
import com.fsck.k9.search.SearchAccount;
|
||||
import com.fsck.k9.search.SearchSpecification;
|
||||
import com.fsck.k9.search.SqlQueryBuilder;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static com.fsck.k9.K9.MAX_SEND_ATTEMPTS;
|
||||
|
@ -141,6 +134,7 @@ public class MessagingController {
|
|||
private final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
private final MemorizingMessagingListener memorizingMessagingListener = new MemorizingMessagingListener();
|
||||
private final TransportProvider transportProvider;
|
||||
private final AccountStatsCollector accountStatsCollector;
|
||||
|
||||
private ImapMessageStore imapMessageStore;
|
||||
|
||||
|
@ -155,19 +149,22 @@ public class MessagingController {
|
|||
NotificationController notificationController = NotificationController.newInstance(appContext);
|
||||
Contacts contacts = Contacts.getInstance(context);
|
||||
TransportProvider transportProvider = TransportProvider.getInstance();
|
||||
inst = new MessagingController(appContext, notificationController, contacts, transportProvider);
|
||||
AccountStatsCollector accountStatsCollector = new DefaultAccountStatsCollector(context);
|
||||
inst = new MessagingController(appContext, notificationController, contacts, transportProvider,
|
||||
accountStatsCollector);
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
MessagingController(Context context, NotificationController notificationController,
|
||||
Contacts contacts, TransportProvider transportProvider) {
|
||||
MessagingController(Context context, NotificationController notificationController, Contacts contacts,
|
||||
TransportProvider transportProvider, AccountStatsCollector accountStatsCollector) {
|
||||
this.context = context;
|
||||
this.notificationController = notificationController;
|
||||
this.contacts = contacts;
|
||||
this.transportProvider = transportProvider;
|
||||
this.accountStatsCollector = accountStatsCollector;
|
||||
|
||||
controllerThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
|
@ -1081,7 +1078,7 @@ public class MessagingController {
|
|||
|
||||
int unreadBeforeStart = 0;
|
||||
try {
|
||||
AccountStats stats = account.getStats(context);
|
||||
AccountStats stats = getAccountStats(account);
|
||||
unreadBeforeStart = stats.unreadMessageCount;
|
||||
|
||||
} catch (MessagingException e) {
|
||||
|
@ -2735,7 +2732,7 @@ public class MessagingController {
|
|||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
AccountStats stats = account.getStats(context);
|
||||
AccountStats stats = getAccountStats(account);
|
||||
listener.accountStatusChanged(account, stats);
|
||||
} catch (MessagingException me) {
|
||||
Timber.e(me, "Count not get unread count for account %s", account.getDescription());
|
||||
|
@ -2745,9 +2742,11 @@ public class MessagingController {
|
|||
});
|
||||
}
|
||||
|
||||
public void getSearchAccountStats(final SearchAccount searchAccount,
|
||||
final MessagingListener listener) {
|
||||
public AccountStats getAccountStats(Account account) throws MessagingException {
|
||||
return accountStatsCollector.getStats(account);
|
||||
}
|
||||
|
||||
public void getSearchAccountStats(final SearchAccount searchAccount, final MessagingListener listener) {
|
||||
threadPool.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -2756,67 +2755,9 @@ public class MessagingController {
|
|||
});
|
||||
}
|
||||
|
||||
public AccountStats getSearchAccountStatsSynchronous(final SearchAccount searchAccount,
|
||||
final MessagingListener listener) {
|
||||
public AccountStats getSearchAccountStatsSynchronous(SearchAccount searchAccount, MessagingListener listener) {
|
||||
AccountStats stats = accountStatsCollector.getSearchAccountStats(searchAccount);
|
||||
|
||||
Preferences preferences = Preferences.getPreferences(context);
|
||||
LocalSearch search = searchAccount.getRelatedSearch();
|
||||
|
||||
// Collect accounts that belong to the search
|
||||
String[] accountUuids = search.getAccountUuids();
|
||||
List<Account> accounts;
|
||||
if (search.searchAllAccounts()) {
|
||||
accounts = preferences.getAccounts();
|
||||
} else {
|
||||
accounts = new ArrayList<>(accountUuids.length);
|
||||
for (int i = 0, len = accountUuids.length; i < len; i++) {
|
||||
String accountUuid = accountUuids[i];
|
||||
accounts.set(i, preferences.getAccount(accountUuid));
|
||||
}
|
||||
}
|
||||
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
|
||||
int unreadMessageCount = 0;
|
||||
int flaggedMessageCount = 0;
|
||||
|
||||
String[] projection = {
|
||||
StatsColumns.UNREAD_COUNT,
|
||||
StatsColumns.FLAGGED_COUNT
|
||||
};
|
||||
|
||||
for (Account account : accounts) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
List<String> queryArgs = new ArrayList<>();
|
||||
ConditionsTreeNode conditions = search.getConditions();
|
||||
SqlQueryBuilder.buildWhereClause(account, conditions, query, queryArgs);
|
||||
|
||||
String selection = query.toString();
|
||||
String[] selectionArgs = queryArgs.toArray(new String[queryArgs.size()]);
|
||||
|
||||
Uri uri = Uri.withAppendedPath(EmailProvider.CONTENT_URI,
|
||||
"account/" + account.getUuid() + "/stats");
|
||||
|
||||
// Query content provider to get the account stats
|
||||
Cursor cursor = cr.query(uri, projection, selection, selectionArgs, null);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
unreadMessageCount += cursor.getInt(0);
|
||||
flaggedMessageCount += cursor.getInt(1);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create AccountStats instance...
|
||||
AccountStats stats = new AccountStats();
|
||||
stats.unreadMessageCount = unreadMessageCount;
|
||||
stats.flaggedMessageCount = flaggedMessageCount;
|
||||
|
||||
// ...and notify the listener
|
||||
if (listener != null) {
|
||||
listener.accountStatusChanged(searchAccount, stats);
|
||||
}
|
||||
|
@ -2832,8 +2773,7 @@ public class MessagingController {
|
|||
|
||||
int unreadMessageCount = 0;
|
||||
try {
|
||||
Folder localFolder = account.getLocalStore().getFolder(folderServerId);
|
||||
unreadMessageCount = localFolder.getUnreadMessageCount();
|
||||
unreadMessageCount = getFolderUnreadMessageCount(account, folderServerId);
|
||||
} catch (MessagingException me) {
|
||||
Timber.e(me, "Count not get unread count for account %s", account.getDescription());
|
||||
}
|
||||
|
@ -2845,6 +2785,11 @@ public class MessagingController {
|
|||
put("getFolderUnread:" + account.getDescription() + ":" + folderServerId, l, unreadRunnable);
|
||||
}
|
||||
|
||||
public int getFolderUnreadMessageCount(Account account, String folderServerId) throws MessagingException {
|
||||
LocalStore localStore = account.getLocalStore();
|
||||
Folder localFolder = localStore.getFolder(folderServerId);
|
||||
return localFolder.getUnreadMessageCount();
|
||||
}
|
||||
|
||||
public boolean isMoveCapable(MessageReference messageReference) {
|
||||
return !messageReference.getUid().startsWith(K9.LOCAL_UID_PREFIX);
|
||||
|
@ -3573,7 +3518,7 @@ public class MessagingController {
|
|||
|
||||
account.setRingNotified(false);
|
||||
try {
|
||||
AccountStats stats = account.getStats(context);
|
||||
AccountStats stats = getAccountStats(account);
|
||||
if (stats == null || stats.unreadMessageCount == 0) {
|
||||
notificationController.clearNewMailNotifications(account);
|
||||
}
|
||||
|
|
|
@ -384,7 +384,7 @@ class ImapSync {
|
|||
|
||||
int unreadBeforeStart = 0;
|
||||
try {
|
||||
AccountStats stats = account.getStats(context);
|
||||
AccountStats stats = controller.getAccountStats(account);
|
||||
unreadBeforeStart = stats.unreadMessageCount;
|
||||
|
||||
} catch (MessagingException e) {
|
||||
|
|
|
@ -44,19 +44,19 @@ public class UnreadWidgetProperties {
|
|||
}
|
||||
|
||||
public int getUnreadCount(Context context) throws MessagingException {
|
||||
MessagingController controller = MessagingController.getInstance(context);
|
||||
BaseAccount baseAccount = getAccount(context);
|
||||
AccountStats stats;
|
||||
switch (type) {
|
||||
case SEARCH_ACCOUNT:
|
||||
MessagingController controller = MessagingController.getInstance(context);
|
||||
stats = controller.getSearchAccountStatsSynchronous((SearchAccount) baseAccount, null);
|
||||
return stats.unreadMessageCount;
|
||||
case ACCOUNT:
|
||||
Account account = (Account) baseAccount;
|
||||
stats = account.getStats(context);
|
||||
stats = controller.getAccountStats(account);
|
||||
return stats.unreadMessageCount;
|
||||
case FOLDER:
|
||||
return ((Account) baseAccount).getFolderUnreadCount(context, folderServerId);
|
||||
return controller.getFolderUnreadMessageCount((Account) baseAccount, folderServerId);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import android.support.annotation.Nullable;
|
|||
import android.text.TextUtils;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.AccountStats;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
|
||||
|
@ -1291,6 +1292,40 @@ public class LocalStore {
|
|||
return folderMap;
|
||||
}
|
||||
|
||||
public AccountStats getAccountStats(LocalSearch search) throws MessagingException {
|
||||
StringBuilder whereBuilder = new StringBuilder();
|
||||
List<String> queryArgs = new ArrayList<>();
|
||||
SqlQueryBuilder.buildWhereClause(account, search.getConditions(), whereBuilder, queryArgs);
|
||||
|
||||
String where = whereBuilder.toString();
|
||||
final String[] selectionArgs = queryArgs.toArray(new String[queryArgs.size()]);
|
||||
|
||||
final String sqlQuery = "SELECT SUM(read=0), SUM(flagged) " +
|
||||
"FROM messages " +
|
||||
"JOIN folders ON (folders.id = messages.folder_id) " +
|
||||
"WHERE (messages.empty = 0 AND messages.deleted = 0)" +
|
||||
(!TextUtils.isEmpty(where) ? " AND (" + where + ")" : "");
|
||||
|
||||
return database.execute(false, new DbCallback<AccountStats>() {
|
||||
@Override
|
||||
public AccountStats doDbWork(SQLiteDatabase db) throws WrappedException, MessagingException {
|
||||
Cursor cursor = db.rawQuery(sqlQuery, selectionArgs);
|
||||
try {
|
||||
AccountStats accountStats = new AccountStats();
|
||||
if (cursor.moveToFirst()) {
|
||||
accountStats.unreadMessageCount = cursor.getInt(0);
|
||||
accountStats.flaggedMessageCount = cursor.getInt(1);
|
||||
}
|
||||
|
||||
return accountStats;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static String getColumnNameForFlag(Flag flag) {
|
||||
switch (flag) {
|
||||
case SEEN: {
|
||||
|
|
|
@ -59,9 +59,6 @@ public class EmailProvider extends ContentProvider {
|
|||
private static final int MESSAGES_THREADED = MESSAGE_BASE + 1;
|
||||
private static final int MESSAGES_THREAD = MESSAGE_BASE + 2;
|
||||
|
||||
private static final int STATS_BASE = 100;
|
||||
private static final int STATS = STATS_BASE;
|
||||
|
||||
|
||||
private static final String MESSAGES_TABLE = "messages";
|
||||
|
||||
|
@ -118,8 +115,6 @@ public class EmailProvider extends ContentProvider {
|
|||
matcher.addURI(AUTHORITY, "account/*/messages", MESSAGES);
|
||||
matcher.addURI(AUTHORITY, "account/*/messages/threaded", MESSAGES_THREADED);
|
||||
matcher.addURI(AUTHORITY, "account/*/thread/#", MESSAGES_THREAD);
|
||||
|
||||
matcher.addURI(AUTHORITY, "account/*/stats", STATS);
|
||||
}
|
||||
|
||||
public interface SpecialColumns {
|
||||
|
@ -190,11 +185,6 @@ public class EmailProvider extends ContentProvider {
|
|||
String FLAGGED_COUNT = "flagged_count";
|
||||
}
|
||||
|
||||
private static final String[] STATS_DEFAULT_PROJECTION = {
|
||||
StatsColumns.UNREAD_COUNT,
|
||||
StatsColumns.FLAGGED_COUNT
|
||||
};
|
||||
|
||||
|
||||
private Preferences mPreferences;
|
||||
|
||||
|
@ -255,17 +245,6 @@ public class EmailProvider extends ContentProvider {
|
|||
cursor = new EmailProviderCacheCursor(accountUuid, cursor, getContext());
|
||||
break;
|
||||
}
|
||||
case STATS: {
|
||||
List<String> segments = uri.getPathSegments();
|
||||
String accountUuid = segments.get(1);
|
||||
|
||||
cursor = getAccountStats(accountUuid, projection, selection, selectionArgs);
|
||||
|
||||
Uri notificationUri = Uri.withAppendedPath(CONTENT_URI, "account/" + accountUuid + "/messages");
|
||||
|
||||
cursor.setNotificationUri(contentResolver, notificationUri);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cursor;
|
||||
|
@ -532,69 +511,6 @@ public class EmailProvider extends ContentProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private Cursor getAccountStats(String accountUuid, String[] columns, final String selection,
|
||||
final String[] selectionArgs) {
|
||||
|
||||
Account account = getAccount(accountUuid);
|
||||
LockableDatabase database = getDatabase(account);
|
||||
|
||||
// Use default projection if none was given
|
||||
String[] sourceProjection = (columns == null) ? STATS_DEFAULT_PROJECTION : columns;
|
||||
|
||||
// Create SQL query string
|
||||
final StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT ");
|
||||
|
||||
// Append projection for the database query
|
||||
// e.g. "SUM(read=0) AS unread_count, SUM(flagged) AS flagged_count"
|
||||
boolean first = true;
|
||||
for (String columnName : sourceProjection) {
|
||||
if (!first) {
|
||||
sql.append(',');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (StatsColumns.UNREAD_COUNT.equals(columnName)) {
|
||||
sql.append("SUM(" + MessageColumns.READ + "=0) AS " + StatsColumns.UNREAD_COUNT);
|
||||
} else if (StatsColumns.FLAGGED_COUNT.equals(columnName)) {
|
||||
sql.append("SUM(" + MessageColumns.FLAGGED + ") AS " + StatsColumns.FLAGGED_COUNT);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Column name not allowed: " + columnName);
|
||||
}
|
||||
}
|
||||
|
||||
// Table selection
|
||||
sql.append(" FROM messages");
|
||||
|
||||
if (containsAny(selection, FOLDERS_COLUMNS)) {
|
||||
sql.append(" JOIN folders ON (folders.id = messages.folder_id)");
|
||||
}
|
||||
|
||||
// WHERE clause
|
||||
sql.append(" WHERE (deleted = 0 AND empty = 0)");
|
||||
if (!TextUtils.isEmpty(selection)) {
|
||||
sql.append(" AND (");
|
||||
sql.append(selection);
|
||||
sql.append(")");
|
||||
}
|
||||
|
||||
// Query the database and return the result cursor
|
||||
try {
|
||||
return database.execute(false, new DbCallback<Cursor>() {
|
||||
@Override
|
||||
public Cursor doDbWork(SQLiteDatabase db) throws WrappedException,
|
||||
UnavailableStorageException {
|
||||
return db.rawQuery(sql.toString(), selectionArgs);
|
||||
}
|
||||
});
|
||||
} catch (UnavailableStorageException e) {
|
||||
throw new RuntimeException("Storage not available", e);
|
||||
} catch (MessagingException e) {
|
||||
throw new RuntimeException("messaging exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Account getAccount(String accountUuid) {
|
||||
if (mPreferences == null) {
|
||||
Context appContext = getContext().getApplicationContext();
|
||||
|
@ -810,18 +726,4 @@ public class EmailProvider extends ContentProvider {
|
|||
return super.isNull(realColumnIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean containsAny(String haystack, String[] needles) {
|
||||
if (haystack == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String needle : needles) {
|
||||
if (haystack.contains(needle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.fsck.k9.provider;
|
|||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -690,11 +691,15 @@ public class MessageProvider extends ContentProvider {
|
|||
|
||||
Object[] values = new Object[2];
|
||||
|
||||
for (Account account : Preferences.getPreferences(getContext()).getAvailableAccounts()) {
|
||||
Context context = getContext();
|
||||
MessagingController controller = MessagingController.getInstance(context);
|
||||
Collection<Account> accounts = Preferences.getPreferences(context).getAvailableAccounts();
|
||||
|
||||
for (Account account : accounts) {
|
||||
if (account.getAccountNumber() == accountNumber) {
|
||||
myAccount = account;
|
||||
try {
|
||||
myAccountStats = account.getStats(getContext());
|
||||
myAccountStats = controller.getAccountStats(account);
|
||||
values[0] = myAccount.getDescription();
|
||||
if (myAccountStats == null) {
|
||||
values[1] = 0;
|
||||
|
|
|
@ -33,6 +33,9 @@ import com.fsck.k9.mailstore.LocalStore;
|
|||
import com.fsck.k9.mailstore.UnavailableStorageException;
|
||||
import com.fsck.k9.notification.NotificationController;
|
||||
import com.fsck.k9.search.LocalSearch;
|
||||
import com.fsck.k9.search.SearchAccount;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -133,6 +136,20 @@ public class MessagingControllerTest {
|
|||
private LocalMessage localMessageToSend1;
|
||||
private volatile boolean hasFetchedMessage = false;
|
||||
|
||||
private AccountStatsCollector accountStatsCollector = new AccountStatsCollector() {
|
||||
@NotNull
|
||||
@Override
|
||||
public AccountStats getSearchAccountStats(@NotNull SearchAccount searchAccount) {
|
||||
return accountStats;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AccountStats getStats(@NotNull Account account) {
|
||||
return accountStats;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws MessagingException {
|
||||
|
@ -140,7 +157,8 @@ public class MessagingControllerTest {
|
|||
MockitoAnnotations.initMocks(this);
|
||||
appContext = ShadowApplication.getInstance().getApplicationContext();
|
||||
|
||||
controller = new MessagingController(appContext, notificationController, contacts, transportProvider);
|
||||
controller = new MessagingController(appContext, notificationController, contacts, transportProvider,
|
||||
accountStatsCollector);
|
||||
|
||||
configureAccount();
|
||||
configureLocalStore();
|
||||
|
@ -898,7 +916,6 @@ 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);
|
||||
when(account.getEmail()).thenReturn("user@host.com");
|
||||
}
|
||||
|
|
|
@ -353,6 +353,7 @@ public class ImapSyncTest {
|
|||
}
|
||||
|
||||
private void setUpMessagingController() throws MessagingException {
|
||||
when(controller.getAccountStats(account)).thenReturn(accountStats);
|
||||
when(controller.getListeners(any(MessagingListener.class))).thenAnswer(new Answer<Set<MessagingListener>>() {
|
||||
@Override
|
||||
public Set<MessagingListener> answer(InvocationOnMock invocation) throws Throwable {
|
||||
|
@ -367,7 +368,6 @@ public class ImapSyncTest {
|
|||
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);
|
||||
when(account.getEmail()).thenReturn("user@host.com");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue