Only count local messages for unread/flagged count

Currently only the Accounts activity uses the new count.

While working on this I realized that the unread/flagged search for
accounts currently looks for unread/flagged messages in all folders, not
all displayable folders without special folders (Trash, Spam, Outbox,
Sent, Drafts) like we used to.
Also, the "All messages" search currently doesn't limit the search to
searchable folders like it is supposed to.
This commit is contained in:
cketti 2012-12-07 05:29:05 +01:00
parent 9a380c69ad
commit 73757af680
4 changed files with 206 additions and 26 deletions

View File

@ -13,8 +13,10 @@ import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.util.Log;
@ -28,6 +30,8 @@ import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.mail.store.StorageManager;
import com.fsck.k9.mail.store.StorageManager.StorageProvider;
import com.fsck.k9.provider.EmailProvider;
import com.fsck.k9.provider.EmailProvider.StatsColumns;
import com.fsck.k9.view.ColorChip;
import java.util.HashMap;
@ -766,16 +770,37 @@ public class Account implements BaseAccount {
if (!isAvailable(context)) {
return null;
}
long startTime = System.currentTimeMillis();
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
};
//TODO: Only count messages in folders that are displayed, exclude special folders like
// Trash, Spam, Outbox, Drafts, Sent.
Cursor cursor = cr.query(uri, projection, null, null, null);
try {
if (cursor.moveToFirst()) {
stats.unreadMessageCount = cursor.getInt(0);
stats.flaggedMessageCount = cursor.getInt(1);
}
} finally {
cursor.close();
}
LocalStore localStore = getLocalStore();
if (K9.measureAccounts()) {
stats.size = localStore.getSize();
}
localStore.getMessageCounts(stats);
long endTime = System.currentTimeMillis();
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Account.getStats() on " + getDescription() + " took " + (endTime - startTime) + " ms;");
return stats;
}

View File

@ -547,26 +547,19 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
}
pendingWork.clear();
MessagingController controller = MessagingController.getInstance(getApplication());
for (BaseAccount account : newAccounts) {
pendingWork.put(account, "true");
if (account instanceof Account) {
pendingWork.put(account, "true");
Account realAccount = (Account)account;
MessagingController.getInstance(getApplication()).getAccountStats(Accounts.this, realAccount, mListener);
Account realAccount = (Account) account;
controller.getAccountStats(this, realAccount, mListener);
} else if (K9.countSearchMessages() && account instanceof SearchAccount) {
pendingWork.put(account, "true");
final SearchAccount searchAccount = (SearchAccount)account;
MessagingController.getInstance(getApplication())
.searchLocalMessages(searchAccount.getRelatedSearch(), new MessagingListener() {
@Override
public void searchStats(AccountStats stats) {
mListener.accountStatusChanged(searchAccount, stats);
}
});
final SearchAccount searchAccount = (SearchAccount) account;
controller.getSearchAccountStats(searchAccount, mListener);
}
}
}
private void onAddNewAccount() {

View File

@ -24,8 +24,10 @@ import android.app.Application;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
@ -69,8 +71,13 @@ import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.fsck.k9.mail.store.LocalStore.PendingCommand;
import com.fsck.k9.mail.store.UnavailableAccountException;
import com.fsck.k9.mail.store.UnavailableStorageException;
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;
/**
@ -3390,22 +3397,90 @@ public class MessagingController implements Runnable {
}
public void getAccountStats(final Context context, final Account account,
final MessagingListener l) {
Runnable unreadRunnable = new Runnable() {
final MessagingListener listener) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
AccountStats stats = account.getStats(context);
l.accountStatusChanged(account, stats);
listener.accountStatusChanged(account, stats);
} catch (MessagingException me) {
Log.e(K9.LOG_TAG, "Count not get unread count for account " + account.getDescription(),
me);
Log.e(K9.LOG_TAG, "Count not get unread count for account " +
account.getDescription(), me);
}
}
};
});
}
put("getAccountStats:" + account.getDescription(), l, unreadRunnable);
public void getSearchAccountStats(final SearchAccount searchAccount,
final MessagingListener listener) {
threadPool.execute(new Runnable() {
@Override
public void run() {
Preferences preferences = Preferences.getPreferences(mApplication);
LocalSearch search = searchAccount.getRelatedSearch();
// Collect accounts that belong to the search
String[] accountUuids = search.getAccountUuids();
Account[] accounts;
if (search.searchAllAccounts()) {
accounts = preferences.getAccounts();
} else {
accounts = new Account[accountUuids.length];
for (int i = 0, len = accountUuids.length; i < len; i++) {
String accountUuid = accountUuids[i];
accounts[i] = preferences.getAccount(accountUuid);
}
}
ContentResolver cr = mApplication.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<String>();
ConditionsTreeNode conditions = search.getConditions();
SqlQueryBuilder.buildWhereClause(account, conditions, query, queryArgs);
// Make sure we don't use the empty string as selection
String selection = (query.length() == 0) ? null : query.toString();
String[] selectionArgs = queryArgs.toArray(EMPTY_STRING_ARRAY);
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.moveToFirst()) {
unreadMessageCount += cursor.getInt(0);
flaggedMessageCount += cursor.getInt(1);
}
} finally {
cursor.close();
}
}
// Create AccountStats instance...
AccountStats stats = new AccountStats();
stats.unreadMessageCount = unreadMessageCount;
stats.flaggedMessageCount = flaggedMessageCount;
// ...and notify the listener
listener.accountStatusChanged(searchAccount, stats);
}
});
}
public void getFolderUnreadMessageCount(final Account account, final String folderName,

View File

@ -56,6 +56,9 @@ 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";
@ -94,6 +97,8 @@ 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 {
@ -136,6 +141,15 @@ public class EmailProvider extends ContentProvider {
public static final String MIME_TYPE = "mime_type";
}
public interface StatsColumns {
public static final String UNREAD_COUNT = "unread_count";
public static final String FLAGGED_COUNT = "flagged_count";
}
private static final String[] STATS_DEFAULT_PROJECTION = {
StatsColumns.UNREAD_COUNT,
StatsColumns.FLAGGED_COUNT
};
private Preferences mPreferences;
@ -196,6 +210,18 @@ public class EmailProvider extends ContentProvider {
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;
@ -364,6 +390,67 @@ 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 (selection != null && selection.contains(SpecialColumns.INTEGRATE)) {
sql.append(" JOIN folders ON (folders.id = messages.folder_id)");
}
// WHERE clause
sql.append(" WHERE (deleted=0 AND (empty IS NULL OR empty!=1))");
if (selection != null) {
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);
}
}
private Account getAccount(String accountUuid) {
if (mPreferences == null) {
Context appContext = getContext().getApplicationContext();