am c3ceed68: Fix ui notifications on folder list changes.

* commit 'c3ceed68948ef6720ae7b861955b4d341f331643':
  Fix ui notifications on folder list changes.
This commit is contained in:
Yu Ping Hu 2013-08-07 10:38:10 -07:00 committed by Android Git Automerger
commit d9521a3f9d
2 changed files with 123 additions and 64 deletions

View File

@ -131,6 +131,12 @@ public class Mailbox extends EmailContent implements MailboxColumns, Parcelable
}; };
private static final int MAILBOX_DISPLAY_NAME_COLUMN = 0; private static final int MAILBOX_DISPLAY_NAME_COLUMN = 0;
/**
* Projection to use when reading {@link MailboxColumns#ACCOUNT_KEY} for a mailbox.
*/
private static final String[] ACCOUNT_KEY_PROJECTION = { MailboxColumns.ACCOUNT_KEY };
private static final int ACCOUNT_KEY_PROJECTION_ACCOUNT_KEY_COLUMN = 0;
public static final long NO_MAILBOX = -1; public static final long NO_MAILBOX = -1;
// Sentinel values for the mSyncInterval field of both Mailbox records // Sentinel values for the mSyncInterval field of both Mailbox records
@ -760,4 +766,18 @@ public class Mailbox extends EmailContent implements MailboxColumns, Parcelable
OUTBOX_PLUS_SYNCING_AND_ACCOUNT_SELECTION, OUTBOX_PLUS_SYNCING_AND_ACCOUNT_SELECTION,
new String[] { Long.toString(accountId) }, null); new String[] { Long.toString(accountId) }, null);
} }
/**
* Get the account id for a mailbox.
* @param context The {@link Context}.
* @param mailboxId The id of the mailbox we're interested in, as a {@link String}.
* @return The account id for the mailbox, or {@link Account#NO_ACCOUNT} if the mailbox doesn't
* exist.
*/
public static long getAccountIdForMailbox(final Context context, final String mailboxId) {
return Utility.getFirstRowLong(context,
Mailbox.CONTENT_URI.buildUpon().appendEncodedPath(mailboxId).build(),
ACCOUNT_KEY_PROJECTION, null, null, null,
ACCOUNT_KEY_PROJECTION_ACCOUNT_KEY_COLUMN, Account.NO_ACCOUNT);
}
} }

View File

@ -577,13 +577,20 @@ public class EmailProvider extends ContentProvider {
db.execSQL(UPDATED_MESSAGE_DELETE + id); db.execSQL(UPDATED_MESSAGE_DELETE + id);
} }
final long accountId;
if (match == MAILBOX_ID) {
accountId = Mailbox.getAccountIdForMailbox(context, id);
} else {
accountId = Account.NO_ACCOUNT;
}
result = db.delete(tableName, whereWithId(id, selection), selectionArgs); result = db.delete(tableName, whereWithId(id, selection), selectionArgs);
if (match == ACCOUNT_ID) { if (match == ACCOUNT_ID) {
notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id); notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id);
resolver.notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); resolver.notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null);
} else if (match == MAILBOX_ID) { } else if (match == MAILBOX_ID) {
notifyUIFolder(id, null); notifyUIFolder(id, accountId);
} else if (match == ATTACHMENT_ID) { } else if (match == ATTACHMENT_ID) {
notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id); notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id);
} }
@ -684,26 +691,30 @@ public class EmailProvider extends ContentProvider {
} }
} }
// These URIs are used for specific UI notifications. We don't use EmailContent.CONTENT_URI
// as the base because that gets spammed.
private static final String UI_NOTIFICATION_AUTHORITY =
EmailContent.EMAIL_PACKAGE_NAME + ".uinotifications";
private static final Uri UIPROVIDER_CONVERSATION_NOTIFIER = private static final Uri UIPROVIDER_CONVERSATION_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uimessages"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uimessages");
private static final Uri UIPROVIDER_FOLDER_NOTIFIER = private static final Uri UIPROVIDER_FOLDER_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uifolder"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uifolder");
private static final Uri UIPROVIDER_FOLDERLIST_NOTIFIER = private static final Uri UIPROVIDER_FOLDERLIST_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uifolders"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uifolders");
private static final Uri UIPROVIDER_ACCOUNT_NOTIFIER = private static final Uri UIPROVIDER_ACCOUNT_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiaccount"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiaccount");
public static final Uri UIPROVIDER_SETTINGS_NOTIFIER = public static final Uri UIPROVIDER_SETTINGS_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uisettings"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uisettings");
private static final Uri UIPROVIDER_ATTACHMENT_NOTIFIER = private static final Uri UIPROVIDER_ATTACHMENT_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiattachment"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiattachment");
private static final Uri UIPROVIDER_ATTACHMENTS_NOTIFIER = private static final Uri UIPROVIDER_ATTACHMENTS_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiattachments"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiattachments");
public static final Uri UIPROVIDER_ALL_ACCOUNTS_NOTIFIER = public static final Uri UIPROVIDER_ALL_ACCOUNTS_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiaccts"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiaccts");
private static final Uri UIPROVIDER_MESSAGE_NOTIFIER = private static final Uri UIPROVIDER_MESSAGE_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uimessage"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uimessage");
private static final Uri UIPROVIDER_RECENT_FOLDERS_NOTIFIER = private static final Uri UIPROVIDER_RECENT_FOLDERS_NOTIFIER =
Uri.parse("content://" + UIProvider.AUTHORITY + "/uirecentfolders"); Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uirecentfolders");
@Override @Override
public Uri insert(Uri uri, ContentValues values) { public Uri insert(Uri uri, ContentValues values) {
@ -744,25 +755,25 @@ public class EmailProvider extends ContentProvider {
resultUri = ContentUris.withAppendedId(uri, longId); resultUri = ContentUris.withAppendedId(uri, longId);
switch(match) { switch(match) {
case MESSAGE: case MESSAGE:
final long mailboxId = values.getAsLong(Message.MAILBOX_KEY);
if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) {
notifyUIConversationMailbox(values.getAsLong(Message.MAILBOX_KEY)); notifyUIConversationMailbox(mailboxId);
} }
notifyUIFolder(mailboxId, values.getAsLong(Message.ACCOUNT_KEY));
break; break;
case MAILBOX: case MAILBOX:
if (values.containsKey(MailboxColumns.TYPE)) { if (values.containsKey(MailboxColumns.TYPE)) {
// Only notify for special mailbox types if (values.getAsInteger(MailboxColumns.TYPE) <
int type = values.getAsInteger(MailboxColumns.TYPE); Mailbox.TYPE_NOT_EMAIL) {
if (type != Mailbox.TYPE_INBOX && type != Mailbox.TYPE_OUTBOX && // Notify the account when a new mailbox is added
type != Mailbox.TYPE_DRAFTS && type != Mailbox.TYPE_SENT && final Long accountId =
type != Mailbox.TYPE_TRASH && type != Mailbox.TYPE_SEARCH) { values.getAsLong(MailboxColumns.ACCOUNT_KEY);
break; if (accountId != null && accountId.longValue() > 0) {
notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, accountId);
notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId);
}
} }
} }
// Notify the account when a new mailbox is added
Long accountId = values.getAsLong(MailboxColumns.ACCOUNT_KEY);
if (accountId != null && accountId.longValue() > 0) {
notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, accountId);
}
break; break;
case ACCOUNT: case ACCOUNT:
updateAccountSyncInterval(longId, values); updateAccountSyncInterval(longId, values);
@ -1438,27 +1449,19 @@ public class EmailProvider extends ContentProvider {
case QUICK_RESPONSE_ID: case QUICK_RESPONSE_ID:
case POLICY_ID: case POLICY_ID:
id = uri.getPathSegments().get(1); id = uri.getPathSegments().get(1);
try { if (match == SYNCED_MESSAGE_ID) {
if (match == SYNCED_MESSAGE_ID) { // For synced messages, first copy the old message to the updated table
// For synced messages, first copy the old message to the updated table // Note the insert or ignore semantics, guaranteeing that only the first
// Note the insert or ignore semantics, guaranteeing that only the first // update will be reflected in the updated message table; therefore this
// update will be reflected in the updated message table; therefore this // row will always have the "original" data
// row will always have the "original" data db.execSQL(UPDATED_MESSAGE_INSERT + id);
db.execSQL(UPDATED_MESSAGE_INSERT + id); } else if (match == MESSAGE_ID) {
} else if (match == MESSAGE_ID) { db.execSQL(UPDATED_MESSAGE_DELETE + id);
db.execSQL(UPDATED_MESSAGE_DELETE + id);
}
result = db.update(tableName, values, whereWithId(id, selection),
selectionArgs);
} catch (SQLiteException e) {
// Null out values (so they aren't cached) and re-throw
values = null;
throw e;
} }
result = db.update(tableName, values, whereWithId(id, selection),
selectionArgs);
if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) { if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) {
if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { handleMessageUpdateNotifications(uri, id, values);
notifyUIConversation(uri);
}
} else if (match == ATTACHMENT_ID) { } else if (match == ATTACHMENT_ID) {
long attId = Integer.parseInt(id); long attId = Integer.parseInt(id);
if (values.containsKey(Attachment.FLAGS)) { if (values.containsKey(Attachment.FLAGS)) {
@ -1477,9 +1480,8 @@ public class EmailProvider extends ContentProvider {
notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, att.mMessageKey); notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, att.mMessageKey);
} }
} }
} else if (match == MAILBOX_ID && values.containsKey(Mailbox.UI_SYNC_STATUS)) { } else if (match == MAILBOX_ID) {
// TODO: should this notify on keys other than sync status? notifyUIFolder(id, Mailbox.getAccountIdForMailbox(context, id));
notifyUIFolder(id, null);
} else if (match == ACCOUNT_ID) { } else if (match == ACCOUNT_ID) {
updateAccountSyncInterval(Long.parseLong(id), values); updateAccountSyncInterval(Long.parseLong(id), values);
// Notify individual account and "all accounts" // Notify individual account and "all accounts"
@ -3055,8 +3057,10 @@ public class EmailProvider extends ContentProvider {
row = getVirtualMailboxRow(acctId, Mailbox.TYPE_UNREAD); row = getVirtualMailboxRow(acctId, Mailbox.TYPE_UNREAD);
mc.addRow(row); mc.addRow(row);
mc.setNotificationUri(context.getContentResolver(), uri); final Uri notifyUri =
c.setNotificationUri(context.getContentResolver(), uri); UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build();
mc.setNotificationUri(context.getContentResolver(), notifyUri);
c.setNotificationUri(context.getContentResolver(), notifyUri);
Cursor[] cursors = new Cursor[] {mc, c}; Cursor[] cursors = new Cursor[] {mc, c};
return new MergeCursor(cursors); return new MergeCursor(cursors);
} }
@ -3436,8 +3440,11 @@ public class EmailProvider extends ContentProvider {
Uri notifyUri = null; Uri notifyUri = null;
switch(match) { switch(match) {
case UI_ALL_FOLDERS: case UI_ALL_FOLDERS:
// TODO: Should this just do uiFolders()?
c = db.rawQuery(genQueryAccountAllMailboxes(uiProjection), new String[] {id}); c = db.rawQuery(genQueryAccountAllMailboxes(uiProjection), new String[] {id});
c = getFolderListCursor(db, c, uiProjection); c = getFolderListCursor(db, c, uiProjection);
notifyUri =
UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build();
break; break;
case UI_RECENT_FOLDERS: case UI_RECENT_FOLDERS:
c = db.rawQuery(genQueryRecentMailboxes(uiProjection), new String[] {id}); c = db.rawQuery(genQueryRecentMailboxes(uiProjection), new String[] {id});
@ -3446,6 +3453,11 @@ public class EmailProvider extends ContentProvider {
case UI_SUBFOLDERS: case UI_SUBFOLDERS:
c = db.rawQuery(genQuerySubfolders(uiProjection), new String[] {id}); c = db.rawQuery(genQuerySubfolders(uiProjection), new String[] {id});
c = getFolderListCursor(db, c, uiProjection); c = getFolderListCursor(db, c, uiProjection);
// Get notifications for any folder changes on this account. This is broader than
// we need but otherwise we'd need for every folder change to notify on all relevant
// subtrees. For now we opt for simplicity.
final long accountId = Mailbox.getAccountIdForMailbox(context, id);
notifyUri = ContentUris.withAppendedId(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId);
break; break;
case UI_MESSAGES: case UI_MESSAGES:
long mailboxId = Long.parseLong(id); long mailboxId = Long.parseLong(id);
@ -4117,9 +4129,48 @@ public class EmailProvider extends ContentProvider {
.build(); .build();
addToSequence(uri, op); addToSequence(uri, op);
} }
return update(ourUri, ourValues, null, null); return update(ourUri, ourValues, null, null);
} }
/**
* Projection for use with getting mailbox & account keys for a message.
*/
private static final String[] MESSAGE_KEYS_PROJECTION =
{ MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY };
private static final int MESSAGE_KEYS_MAILBOX_KEY_COLUMN = 0;
private static final int MESSAGE_KEYS_ACCOUNT_KEY_COLUMN = 1;
/**
* Notify necessary UI components in response to a message update.
* @param uri The {@link Uri} for this message update.
* @param messageId The id of the message that's been updated.
* @param values The {@link ContentValues} that were updated in the message.
*/
private void handleMessageUpdateNotifications(final Uri uri, final String messageId,
final ContentValues values) {
if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) {
notifyUIConversation(uri);
}
// TODO: Ideally, also test that the values actually changed.
if (values.containsKey(MessageColumns.FLAG_READ) ||
values.containsKey(MessageColumns.MAILBOX_KEY)) {
final Cursor c = query(
Message.CONTENT_URI.buildUpon().appendEncodedPath(messageId).build(),
MESSAGE_KEYS_PROJECTION, null, null, null);
if (c != null) {
try {
if (c.moveToFirst()) {
notifyUIFolder(c.getLong(MESSAGE_KEYS_MAILBOX_KEY_COLUMN),
c.getLong(MESSAGE_KEYS_ACCOUNT_KEY_COLUMN));
}
} finally {
c.close();
}
}
}
}
public static final String PICKER_UI_ACCOUNT = "picker_ui_account"; public static final String PICKER_UI_ACCOUNT = "picker_ui_account";
public static final String PICKER_MAILBOX_TYPE = "picker_mailbox_type"; public static final String PICKER_MAILBOX_TYPE = "picker_mailbox_type";
public static final String PICKER_MESSAGE_ID = "picker_message_id"; public static final String PICKER_MESSAGE_ID = "picker_message_id";
@ -4248,30 +4299,18 @@ public class EmailProvider extends ContentProvider {
* Notify about a folder update. Because folder changes can affect the conversation cursor's * Notify about a folder update. Because folder changes can affect the conversation cursor's
* extras, the conversation must also be notified here. * extras, the conversation must also be notified here.
* @param folderId the folder id to be notified * @param folderId the folder id to be notified
* @param accountId the account id to be notified (for folder list notification); if null, then * @param accountId the account id to be notified (for folder list notification).
* lookup the accountId from the folder.
*/ */
private void notifyUIFolder(String folderId, String accountId) { private void notifyUIFolder(final String folderId, final long accountId) {
notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId); notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId);
notifyUI(UIPROVIDER_FOLDER_NOTIFIER, folderId); notifyUI(UIPROVIDER_FOLDER_NOTIFIER, folderId);
if (accountId == null) { if (accountId != Account.NO_ACCOUNT) {
try {
final Mailbox mailbox = Mailbox.restoreMailboxWithId(getContext(),
Long.parseLong(folderId));
if (mailbox != null) {
accountId = Long.toString(mailbox.mAccountKey);
}
} catch (NumberFormatException e) {
// Bad folderId, so we can't lookup account.
}
}
if (accountId != null) {
notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId); notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId);
} }
} }
private void notifyUIFolder(long folderId, long accountId) { private void notifyUIFolder(final long folderId, final long accountId) {
notifyUIFolder(Long.toString(folderId), Long.toString(accountId)); notifyUIFolder(Long.toString(folderId), accountId);
} }
private void notifyUI(Uri uri, String id) { private void notifyUI(Uri uri, String id) {