Add URI's that atomically add a value to a particular field (Account or Mailbox)
* Message, etc. could be added, if this had a use case * Unit test added for both Account and Mailbox cases * Eclipse changed some parens around; it won't happen again
This commit is contained in:
parent
d366346a64
commit
c0c9c33322
@ -70,6 +70,9 @@ public abstract class EmailContent {
|
||||
};
|
||||
private static final int ID_PROJECTION_COLUMN = 0;
|
||||
|
||||
public static final String FIELD_COLUMN_NAME = "field";
|
||||
public static final String ADD_COLUMN_NAME = "add";
|
||||
|
||||
// Newly created objects get this id
|
||||
private static final int NOT_SAVED = -1;
|
||||
// The base Uri that this piece of content came from
|
||||
@ -275,7 +278,7 @@ public abstract class EmailContent {
|
||||
* If the message has no body, a new body is inserted for the message.
|
||||
* Warning: the argument "values" is modified by this method, setting MESSAGE_KEY.
|
||||
*/
|
||||
public static void updateBodyWithMessageId(Context context, long messageId,
|
||||
public static void updateBodyWithMessageId(Context context, long messageId,
|
||||
ContentValues values) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
long bodyId = lookupBodyIdWithMessageId(resolver, messageId);
|
||||
@ -754,7 +757,6 @@ public abstract class EmailContent {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -797,7 +799,8 @@ public abstract class EmailContent {
|
||||
public static final class Account extends EmailContent implements AccountColumns, Parcelable {
|
||||
public static final String TABLE_NAME = "Account";
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/account");
|
||||
|
||||
public static final Uri ADD_TO_FIELD_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/accountIdAddToField");
|
||||
|
||||
public final static int FLAGS_NOTIFY_NEW_MAIL = 1;
|
||||
public final static int FLAGS_VIBRATE = 2;
|
||||
@ -1750,6 +1753,8 @@ public abstract class EmailContent {
|
||||
public static final class Mailbox extends EmailContent implements SyncColumns, MailboxColumns {
|
||||
public static final String TABLE_NAME = "Mailbox";
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailbox");
|
||||
public static final Uri ADD_TO_FIELD_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdAddToField");
|
||||
|
||||
public String mDisplayName;
|
||||
public String mServerId;
|
||||
|
@ -66,11 +66,13 @@ public class EmailProvider extends ContentProvider {
|
||||
private static final int ACCOUNT = ACCOUNT_BASE;
|
||||
private static final int ACCOUNT_MAILBOXES = ACCOUNT_BASE + 1;
|
||||
private static final int ACCOUNT_ID = ACCOUNT_BASE + 2;
|
||||
private static final int ACCOUNT_ID_ADD_TO_FIELD = ACCOUNT_BASE + 3;
|
||||
|
||||
private static final int MAILBOX_BASE = 0x1000;
|
||||
private static final int MAILBOX = MAILBOX_BASE;
|
||||
private static final int MAILBOX_MESSAGES = MAILBOX_BASE + 1;
|
||||
private static final int MAILBOX_ID = MAILBOX_BASE + 2;
|
||||
private static final int MAILBOX_ID_ADD_TO_FIELD = MAILBOX_BASE + 3;
|
||||
|
||||
private static final int MESSAGE_BASE = 0x2000;
|
||||
private static final int MESSAGE = MESSAGE_BASE;
|
||||
@ -146,6 +148,8 @@ public class EmailProvider extends ContentProvider {
|
||||
private static final String DELETE_BODY = "delete from " + Body.TABLE_NAME +
|
||||
" where " + BodyColumns.MESSAGE_KEY + '=';
|
||||
|
||||
private static final String ID_EQUALS = EmailContent.RECORD_ID + "=?";
|
||||
|
||||
static {
|
||||
// Email URI matching table
|
||||
UriMatcher matcher = sURIMatcher;
|
||||
@ -199,9 +203,13 @@ public class EmailProvider extends ContentProvider {
|
||||
// A specific hostauth
|
||||
matcher.addURI(EMAIL_AUTHORITY, "hostauth/#", HOSTAUTH_ID);
|
||||
|
||||
// Atomically a constant value to a particular field of a mailbox/account
|
||||
matcher.addURI(EMAIL_AUTHORITY, "mailboxIdAddToField/#", MAILBOX_ID_ADD_TO_FIELD);
|
||||
matcher.addURI(EMAIL_AUTHORITY, "accountIdAddToField/#", ACCOUNT_ID_ADD_TO_FIELD);
|
||||
|
||||
/**
|
||||
* THIS URI HAS SPECIAL SEMANTICS
|
||||
* ITS USE IS INDENTED FOR THE UI APPLICATION TO MARK CHANGES THAT NEED TO BE SYNCED BACK
|
||||
* ITS USE IS INTENDED FOR THE UI APPLICATION TO MARK CHANGES THAT NEED TO BE SYNCED BACK
|
||||
* TO A SERVER VIA A SYNC ADAPTER
|
||||
*/
|
||||
matcher.addURI(EMAIL_AUTHORITY, "syncedMessage/#", SYNCED_MESSAGE_ID);
|
||||
@ -876,7 +884,40 @@ public class EmailProvider extends ContentProvider {
|
||||
values.remove(MailboxColumns.UNREAD_COUNT);
|
||||
}
|
||||
|
||||
String id;
|
||||
switch (match) {
|
||||
case MAILBOX_ID_ADD_TO_FIELD:
|
||||
case ACCOUNT_ID_ADD_TO_FIELD:
|
||||
if (!mInTransaction) {
|
||||
db.beginTransaction();
|
||||
}
|
||||
id = uri.getPathSegments().get(1);
|
||||
String field = values.getAsString(EmailContent.FIELD_COLUMN_NAME);
|
||||
Long add = values.getAsLong(EmailContent.ADD_COLUMN_NAME);
|
||||
if (field == null || add == null) {
|
||||
throw new IllegalArgumentException("No field/add specified " + uri);
|
||||
}
|
||||
Cursor c = db.query(TABLE_NAMES[table],
|
||||
new String[] {EmailContent.RECORD_ID, field}, whereWithId(id, selection),
|
||||
selectionArgs, null, null, null);
|
||||
try {
|
||||
result = 0;
|
||||
ContentValues cv = new ContentValues();
|
||||
String[] bind = new String[1];
|
||||
while (c.moveToNext()) {
|
||||
bind[0] = c.getString(0);
|
||||
long value = c.getLong(1) + add;
|
||||
cv.put(field, value);
|
||||
result = db.update(TABLE_NAMES[table], cv, ID_EQUALS, bind);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
if (!mInTransaction) {
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
break;
|
||||
case BODY_ID:
|
||||
case MESSAGE_ID:
|
||||
case SYNCED_MESSAGE_ID:
|
||||
@ -885,7 +926,7 @@ public class EmailProvider extends ContentProvider {
|
||||
case MAILBOX_ID:
|
||||
case ACCOUNT_ID:
|
||||
case HOSTAUTH_ID:
|
||||
String id = uri.getPathSegments().get(1);
|
||||
id = uri.getPathSegments().get(1);
|
||||
if (match == SYNCED_MESSAGE_ID) {
|
||||
// For synced messages, first copy the old message to the updated table
|
||||
// Note the insert or ignore semantics, guaranteeing that only the first
|
||||
|
@ -22,6 +22,7 @@ import com.android.email.R;
|
||||
import com.android.email.activity.MessageList;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.AccountColumns;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
@ -62,7 +63,9 @@ public class MailService extends Service {
|
||||
|
||||
private static final String EXTRA_CHECK_ACCOUNT = "com.android.email.intent.extra.ACCOUNT";
|
||||
private static final String EXTRA_ACCOUNT_INFO = "com.android.email.intent.extra.ACCOUNT_INFO";
|
||||
private static final String EXTRA_MESSAGE_COUNT = "com.android.email.intent.extra.COUNT";
|
||||
|
||||
private static final String[] NEW_MESSAGE_COUNT_PROJECTION =
|
||||
new String[] {AccountColumns.NEW_MESSAGE_COUNT};
|
||||
|
||||
private Controller.Result mControllerCallback = new ControllerResults();
|
||||
|
||||
@ -120,21 +123,20 @@ public class MailService extends Service {
|
||||
}
|
||||
context.getContentResolver().update(uri, mClearNewMessages, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Entry point for asynchronous message services (e.g. push mode) to post notifications of new
|
||||
* messages. This assumes that the push provider has already synced the messages into the
|
||||
* appropriate database - this simply triggers the notification mechanism.
|
||||
*
|
||||
*
|
||||
* @param context a context
|
||||
* @param accountId the id of the account that is reporting new messages
|
||||
* @param newCount the number of new messages
|
||||
*/
|
||||
public static void actionNotifyNewMessages(Context context, long accountId, int newCount) {
|
||||
public static void actionNotifyNewMessages(Context context, long accountId) {
|
||||
Intent i = new Intent(ACTION_NOTIFY_MAIL);
|
||||
i.setClass(context, MailService.class);
|
||||
i.putExtra(EXTRA_CHECK_ACCOUNT, accountId);
|
||||
i.putExtra(EXTRA_MESSAGE_COUNT, newCount);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
@ -156,7 +158,7 @@ public class MailService extends Service {
|
||||
// If we have the data, restore the last-sync-times for each account
|
||||
// These are cached in the wakeup intent in case the process was killed.
|
||||
restoreSyncReports(intent);
|
||||
|
||||
|
||||
// Sync a specific account if given
|
||||
long checkAccountId = intent.getLongExtra(EXTRA_CHECK_ACCOUNT, -1);
|
||||
if (checkAccountId != -1) {
|
||||
@ -185,7 +187,21 @@ public class MailService extends Service {
|
||||
stopSelf(startId);
|
||||
} else if (ACTION_NOTIFY_MAIL.equals(action)) {
|
||||
long accountId = intent.getLongExtra(EXTRA_CHECK_ACCOUNT, -1);
|
||||
int newMessageCount = intent.getIntExtra(EXTRA_MESSAGE_COUNT, -1);
|
||||
// Get the current new message count
|
||||
Cursor c = getContentResolver().query(
|
||||
ContentUris.withAppendedId(Account.CONTENT_URI, accountId),
|
||||
NEW_MESSAGE_COUNT_PROJECTION, null, null, null);
|
||||
int newMessageCount = 0;
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
newMessageCount = c.getInt(0);
|
||||
} else {
|
||||
// If the account no longer exists, set to -1 (which is handled below)
|
||||
accountId = -1;
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
if (Config.LOGD && Email.DEBUG) {
|
||||
Log.d(Email.LOG_TAG, "*** MailService: notify accountId=" + Long.toString(accountId)
|
||||
+ " count=" + newMessageCount);
|
||||
|
@ -18,8 +18,10 @@
|
||||
package com.android.exchange.adapter;
|
||||
|
||||
import com.android.email.mail.Address;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailProvider;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.AccountColumns;
|
||||
import com.android.email.provider.EmailContent.Attachment;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
import com.android.email.provider.EmailContent.Message;
|
||||
@ -464,28 +466,17 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should be implemented using an "add to unread messages" URI,
|
||||
// and then it could be handled in the previous section as just another "op"
|
||||
int totalNewCount = 0;
|
||||
if (notifyCount > 0) {
|
||||
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, mAccount.mId);
|
||||
Cursor c = mContentResolver.query(uri,
|
||||
new String[] { Account.NEW_MESSAGE_COUNT }, null, null, null);
|
||||
try {
|
||||
if (c.moveToNext()) {
|
||||
int oldCount = c.getInt(0);
|
||||
ContentValues cv = new ContentValues();
|
||||
totalNewCount = oldCount + notifyCount;
|
||||
cv.put(Account.NEW_MESSAGE_COUNT, totalNewCount);
|
||||
mContentResolver.update(uri, cv, null, null);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (totalNewCount > 0) {
|
||||
MailService.actionNotifyNewMessages(mContext, mAccount.mId, totalNewCount);
|
||||
// Use the new atomic add URI in EmailProvider
|
||||
// We could add this to the operations being done, but it's not strictly
|
||||
// speaking necessary, as the previous batch preserves the integrity of the
|
||||
// database, whereas this is purely for notification purposes, and is itself atomic
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT);
|
||||
cv.put(EmailContent.ADD_COLUMN_NAME, notifyCount);
|
||||
Uri uri = ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, mAccount.mId);
|
||||
mContentResolver.update(uri, cv, null, null);
|
||||
MailService.actionNotifyNewMessages(mContext, mAccount.mId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +445,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
||||
|
||||
// 3. delete first message
|
||||
resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null);
|
||||
|
||||
|
||||
// 4. verify body for second message wasn't deleted
|
||||
assertNotNull(loadBodyForMessageId(message2Id));
|
||||
|
||||
@ -483,7 +483,6 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
||||
true, mMockContext);
|
||||
long message2Id = message2.mId;
|
||||
//verify body is there
|
||||
Body body = loadBodyForMessageId(message2Id);
|
||||
assertNotNull(loadBodyForMessageId(message2Id));
|
||||
|
||||
// 3. delete first message
|
||||
@ -1030,4 +1029,34 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
||||
String newStr = EmailProvider.createIndex(Message.TABLE_NAME, MessageColumns.TIMESTAMP);
|
||||
assertEquals(newStr, oldStr);
|
||||
}
|
||||
|
||||
public void testIdAddToField() {
|
||||
ContentResolver cr = mMockContext.getContentResolver();
|
||||
ContentValues cv = new ContentValues();
|
||||
|
||||
// Try changing the newMessageCount of an account
|
||||
Account account = ProviderTestUtils.setupAccount("field-add", true, mMockContext);
|
||||
int startCount = account.mNewMessageCount;
|
||||
// "field" and "add" are the two required elements
|
||||
cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT);
|
||||
cv.put(EmailContent.ADD_COLUMN_NAME, 17);
|
||||
cr.update(ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, account.mId),
|
||||
cv, null, null);
|
||||
Account restoredAccount = Account.restoreAccountWithId(mMockContext, account.mId);
|
||||
assertEquals(17 + startCount, restoredAccount.mNewMessageCount);
|
||||
cv.put(EmailContent.ADD_COLUMN_NAME, -11);
|
||||
cr.update(ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, account.mId),
|
||||
cv, null, null);
|
||||
restoredAccount = Account.restoreAccountWithId(mMockContext, account.mId);
|
||||
assertEquals(17 - 11 + startCount, restoredAccount.mNewMessageCount);
|
||||
|
||||
// Now try with a mailbox
|
||||
Mailbox boxA = ProviderTestUtils.setupMailbox("boxA", account.mId, true, mMockContext);
|
||||
assertEquals(0, boxA.mUnreadCount);
|
||||
cv.put(EmailContent.FIELD_COLUMN_NAME, MailboxColumns.UNREAD_COUNT);
|
||||
cv.put(EmailContent.ADD_COLUMN_NAME, 11);
|
||||
cr.update(ContentUris.withAppendedId(Mailbox.ADD_TO_FIELD_URI, boxA.mId), cv, null, null);
|
||||
Mailbox restoredBoxA = Mailbox.restoreMailboxWithId(mMockContext, boxA.mId);
|
||||
assertEquals(11, restoredBoxA.mUnreadCount);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user