Handle upsync of EAS contact "group" (category) rename/delete

Bug: 3211907
Change-Id: I7bec90dae7c223b4bd0d0f366d18cac37e53fbcc
This commit is contained in:
Marc Blank 2010-11-23 13:33:30 -08:00
parent 46e60b51e2
commit fb3c389a14
2 changed files with 71 additions and 21 deletions

View File

@ -17,7 +17,6 @@
package com.android.exchange; package com.android.exchange;
import com.android.email.Email; import com.android.email.Email;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.AccountColumns; import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.Mailbox; import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.MailboxColumns; import com.android.email.provider.EmailContent.MailboxColumns;
@ -35,6 +34,7 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts; import android.provider.ContactsContract.RawContacts;
import android.util.Log; import android.util.Log;
@ -43,7 +43,7 @@ public class ContactsSyncAdapterService extends Service {
private static SyncAdapterImpl sSyncAdapter = null; private static SyncAdapterImpl sSyncAdapter = null;
private static final Object sSyncAdapterLock = new Object(); private static final Object sSyncAdapterLock = new Object();
private static final String[] ID_PROJECTION = new String[] {EmailContent.RECORD_ID}; private static final String[] ID_PROJECTION = new String[] {"_id"};
private static final String ACCOUNT_AND_TYPE_CONTACTS = private static final String ACCOUNT_AND_TYPE_CONTACTS =
MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.TYPE + '=' + Mailbox.TYPE_CONTACTS; MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.TYPE + '=' + Mailbox.TYPE_CONTACTS;
@ -85,6 +85,15 @@ public class ContactsSyncAdapterService extends Service {
return sSyncAdapter.getSyncAdapterBinder(); return sSyncAdapter.getSyncAdapterBinder();
} }
private static boolean hasDirtyRows(ContentResolver resolver, Uri uri, String dirtyColumn) {
Cursor c = resolver.query(uri, ID_PROJECTION, dirtyColumn + "=1", null, null);
try {
return c.getCount() > 0;
} finally {
c.close();
}
}
/** /**
* Partial integration with system SyncManager; we tell our EAS ExchangeService to start a * Partial integration with system SyncManager; we tell our EAS ExchangeService to start a
* contacts sync when we get the signal from SyncManager. * contacts sync when we get the signal from SyncManager.
@ -95,22 +104,30 @@ public class ContactsSyncAdapterService extends Service {
String authority, ContentProviderClient provider, SyncResult syncResult) String authority, ContentProviderClient provider, SyncResult syncResult)
throws OperationCanceledException { throws OperationCanceledException {
ContentResolver cr = context.getContentResolver(); ContentResolver cr = context.getContentResolver();
Log.i(TAG, "performSync"); if (Email.DEBUG) {
Log.d(TAG, "performSync");
}
// If we've been asked to do an upload, make sure we've got work to do
if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) { if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
Uri uri = RawContacts.CONTENT_URI.buildUpon() Uri uri = RawContacts.CONTENT_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name) .appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE, Email.EXCHANGE_ACCOUNT_MANAGER_TYPE) .appendQueryParameter(RawContacts.ACCOUNT_TYPE, Email.EXCHANGE_ACCOUNT_MANAGER_TYPE)
.build(); .build();
Cursor c = cr.query(uri, // See if we've got dirty contacts or dirty groups containing our contacts
new String[] {RawContacts._ID}, RawContacts.DIRTY + "=1", null, null); boolean changed = hasDirtyRows(cr, uri, RawContacts.DIRTY);
try { if (!changed) {
if (!c.moveToFirst()) { uri = Groups.CONTENT_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE,
Email.EXCHANGE_ACCOUNT_MANAGER_TYPE)
.build();
changed = hasDirtyRows(cr, uri, Groups.DIRTY);
}
if (!changed) {
Log.i(TAG, "Upload sync; no changes"); Log.i(TAG, "Upload sync; no changes");
return; return;
} }
} finally {
c.close();
}
} }
// Find the (EmailProvider) account associated with this email address // Find the (EmailProvider) account associated with this email address

View File

@ -75,7 +75,10 @@ public class ContactsSyncAdapter extends AbstractSyncAdapter {
private static final String SERVER_ID_SELECTION = RawContacts.SOURCE_ID + "=?"; private static final String SERVER_ID_SELECTION = RawContacts.SOURCE_ID + "=?";
private static final String CLIENT_ID_SELECTION = RawContacts.SYNC1 + "=?"; private static final String CLIENT_ID_SELECTION = RawContacts.SYNC1 + "=?";
private static final String[] ID_PROJECTION = new String[] {RawContacts._ID}; private static final String[] ID_PROJECTION = new String[] {RawContacts._ID};
private static final String[] GROUP_PROJECTION = new String[] {Groups.SOURCE_ID}; private static final String[] GROUP_TITLE_PROJECTION = new String[] {Groups.TITLE};
private static final String MIMETYPE_GROUP_MEMBERSHIP_AND_ID_EQUALS = Data.MIMETYPE + "='" +
GroupMembership.CONTENT_ITEM_TYPE + "' AND " + GroupMembership.GROUP_ROW_ID + "=?";
private static final String[] GROUPS_ID_PROJECTION = new String[] {Groups._ID};
private static final ArrayList<NamedContentValues> EMPTY_ARRAY_NAMEDCONTENTVALUES private static final ArrayList<NamedContentValues> EMPTY_ARRAY_NAMEDCONTENTVALUES
= new ArrayList<NamedContentValues>(); = new ArrayList<NamedContentValues>();
@ -1742,17 +1745,47 @@ public class ContactsSyncAdapter extends AbstractSyncAdapter {
} }
} }
private void dirtyContactsWithinDirtyGroups() {
ContentResolver cr = mService.mContentResolver;
Cursor c = cr.query(uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI),
GROUPS_ID_PROJECTION, Groups.DIRTY + "=1", null, null);
try {
if (c.getCount() > 0) {
String[] updateArgs = new String[1];
ContentValues updateValues = new ContentValues();
while (c.moveToNext()) {
// For each, "touch" all data rows with this group id; this will mark contacts
// in this group as dirty (per ContactsContract). We will then know to upload
// them to the server with the modified group information
long id = c.getLong(0);
updateValues.put(GroupMembership.GROUP_ROW_ID, id);
updateArgs[0] = Long.toString(id);
cr.update(Data.CONTENT_URI, updateValues,
MIMETYPE_GROUP_MEMBERSHIP_AND_ID_EQUALS, updateArgs);
}
// Really delete groups that are marked deleted
cr.delete(uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI), Groups.DELETED + "=1",
null);
// Clear the dirty flag for all of our groups
updateValues.clear();
updateValues.put(Groups.DIRTY, 0);
cr.update(uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI), updateValues, null,
null);
}
} finally {
c.close();
}
}
@Override @Override
public boolean sendLocalChanges(Serializer s) throws IOException { public boolean sendLocalChanges(Serializer s) throws IOException {
// First, let's find Contacts that have changed.
ContentResolver cr = mService.mContentResolver; ContentResolver cr = mService.mContentResolver;
Uri uri = RawContactsEntity.CONTENT_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, mAccount.mEmailAddress)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE,
com.android.email.Email.EXCHANGE_ACCOUNT_MANAGER_TYPE)
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build();
// Find any groups of ours that are dirty and dirty those groups' members
dirtyContactsWithinDirtyGroups();
// First, let's find Contacts that have changed.
Uri uri = uriWithAccountAndIsSyncAdapter(RawContactsEntity.CONTENT_URI);
if (getSyncKey().equals("0")) { if (getSyncKey().equals("0")) {
return false; return false;
} }
@ -1863,7 +1896,7 @@ public class ContactsSyncAdapter extends AbstractSyncAdapter {
for (int id: groupIds) { for (int id: groupIds) {
// Since we get id's from the provider, we need to find their names // Since we get id's from the provider, we need to find their names
Cursor c = cr.query(ContentUris.withAppendedId(Groups.CONTENT_URI, id), Cursor c = cr.query(ContentUris.withAppendedId(Groups.CONTENT_URI, id),
GROUP_PROJECTION, null, null, null); GROUP_TITLE_PROJECTION, null, null, null);
try { try {
// Presumably, this should always succeed, but ... // Presumably, this should always succeed, but ...
if (c.moveToFirst()) { if (c.moveToFirst()) {