Handle upsync of EAS contact "group" (category) rename/delete
Bug: 3211907 Change-Id: I7bec90dae7c223b4bd0d0f366d18cac37e53fbcc
This commit is contained in:
parent
46e60b51e2
commit
fb3c389a14
@ -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
|
||||||
|
@ -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()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user