Finaly SyncAdapter works on Add and Update.
author"Vincent Veronis"
Wed, 13 Apr 2011 22:51:44 +0200
changeset 883 4e23720db26d
parent 882 5cf109742815
child 884 b5104ccb1916
Finaly SyncAdapter works on Add and Update.
src/com/beem/project/beem/account/SyncAdapterService.java
--- a/src/com/beem/project/beem/account/SyncAdapterService.java	Thu Mar 31 21:49:28 2011 +0200
+++ b/src/com/beem/project/beem/account/SyncAdapterService.java	Wed Apr 13 22:51:44 2011 +0200
@@ -9,7 +9,6 @@
 import org.jivesoftware.smack.RosterEntry;
 import org.jivesoftware.smack.XMPPConnection;
 import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.util.StringUtils;
 
 import android.accounts.Account;
 import android.accounts.OperationCanceledException;
@@ -17,15 +16,18 @@
 import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.OperationApplicationException;
 import android.content.SyncResult;
+import android.database.Cursor;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.provider.ContactsContract;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.util.Log;
 
@@ -72,56 +74,94 @@
 	BeemConnection beemco = new BeemConnection(mContext.getSharedPreferences(account.name, MODE_PRIVATE), null);
 	beemco.setNoPresence();
 	XMPPConnection con = new XMPPConnection(beemco.getConnectionConfiguration());
+	Roster roster = null;
 	try {
 	    con.connect();
 	    con.login(beemco.getLogin(), beemco.getPassword(), "BEEM_SYNC_ADAPTER");
+	    roster = con.getRoster();
 
-	    Roster roster = con.getRoster();
-	    if (roster != null) {
-		for (RosterEntry entry : roster.getEntries()) {
-		    if (entry != null) {
-			addEntry(account, entry);
-		    }
-		}
-	    }
-	} catch (XMPPException e) {	
+	} catch (XMPPException e) {
 	    Log.e(TAG, "Error while connecting with syncAdapter", e);
+	} catch (IllegalStateException e) {
+	    Log.e(TAG, "Not connected to server", e);
+	}
+	if (roster != null) {
+	    manageRoster(roster, account);
 	}
 
 	con.disconnect();
 
     }
 
-    private static void addEntry(Account account, RosterEntry entry) {
+    private static void executeOperation(ArrayList<ContentProviderOperation> ops) {
+	try {
+	    mContentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
+	} catch (RemoteException e) {
+	    Log.d(TAG, "Error during sync of contact", e);
+	} catch (OperationApplicationException e) {
+	    Log.d(TAG, "Error during sync of contact", e);
+	}
+    }
+    
+    private static void manageRoster(final Roster r, final Account a) {
 	ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
 
-	int rawContactInsertIndex = ops.size();
+	for (RosterEntry entry : r.getEntries()) {
+	    if (entry != null) {
+		manageEntry(ops, a, entry);
+	    }
+	    if (ops.size() > 100)
+		executeOperation(ops);
+	}
+	if (ops.size() > 0)
+	    executeOperation(ops);
+    }
 
-	ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
-	builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
-	builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
-	builder.withValue(RawContacts.SYNC1, entry.getUser());
-	ops.add(builder.build());
+    private static void manageEntry(ArrayList<ContentProviderOperation> ops, Account account, RosterEntry entry) {
 
-	builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-	builder.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex);
-	builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
-	builder.withValue(StructuredName.DISPLAY_NAME, entry.getUser());
-	ops.add(builder.build());
-
-	builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
-	builder.withValueBackReference(Data.RAW_CONTACT_ID, 0);
-	builder.withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
-	builder.withValue(Im.DATA, entry.getUser());
-	builder.withValue(Im.PROTOCOL, Im.PROTOCOL_JABBER);
-	ops.add(builder.build());
-
-	try {
-	    mContentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
-	    Log.i(TAG, "added contact " + entry.getUser());
-	} catch (Exception e) {
-	    Log.d(TAG, "Error during add of contact", e);
+	long rawContactID = getRawContactID(account.name, entry.getUser());
+	if (rawContactID == -1) { // Not found in database, add new 	    
+	    ContentValues values = new ContentValues();
+	    values.put(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type);
+	    values.put(ContactsContract.RawContacts.ACCOUNT_NAME, account.name);
+	    values.put(ContactsContract.RawContacts.SOURCE_ID, entry.getUser());
+	    Uri rawContactUri = mContentResolver.insert(ContactsContract.RawContacts.CONTENT_URI, values);
+	    rawContactID = ContentUris.parseId(rawContactUri);
+	    values.clear();
+	    ContentProviderOperation.Builder builder = buildStructuredName(ContentProviderOperation
+		.newInsert(ContactsContract.Data.CONTENT_URI), entry, rawContactID);
+	    ops.add(builder.build());
+	} else { // Found, update
+	    // if newUpdate instead of newInster ... fail update : all rows = 1 row
+	    ContentProviderOperation.Builder builder = buildStructuredName(ContentProviderOperation
+		.newInsert(ContactsContract.Data.CONTENT_URI), entry, rawContactID);
+	    ops.add(builder.build());
 	}
     }
 
+    private static ContentProviderOperation.Builder buildStructuredName(ContentProviderOperation.Builder builder,
+	RosterEntry entry, long rawContactID) {
+	String displayName = entry.getName() != null ? entry.getName() : entry.getUser();
+	builder.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactID);
+	builder.withValue(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+	builder.withValue(StructuredName.DISPLAY_NAME, displayName);
+	return builder;
+    }
+
+    private static long getRawContactID(String account, String jid) {
+	long authorId = -1;
+	final Cursor c = mContentResolver.query(ContactsContract.RawContacts.CONTENT_URI, new String[] {
+	    ContactsContract.RawContacts._ID, ContactsContract.RawContacts.SOURCE_ID },
+	    ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND " + ContactsContract.RawContacts.SOURCE_ID + "=?",
+	    new String[] { account, jid }, null);
+	try {
+	    if (c.moveToFirst())
+		authorId = c.getInt(c.getColumnIndex(ContactsContract.RawContacts._ID));
+	} finally {
+	    if (c != null)
+		c.close();
+	}
+	return authorId;
+    }
+
 }