Try to do an update before inserting.
diff --git a/src/com/android/contacts/AttachImage.java b/src/com/android/contacts/AttachImage.java
index fd820e2..c8b6322 100644
--- a/src/com/android/contacts/AttachImage.java
+++ b/src/com/android/contacts/AttachImage.java
@@ -16,19 +16,32 @@
package com.android.contacts;
+import com.google.android.collect.Maps;
+
import android.app.Activity;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.widget.Toast;
+import com.android.contacts.model.ExchangeSource;
+import com.android.contacts.model.GoogleSource;
+
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
/**
* Provides an external interface for other applications to attach images
@@ -40,39 +53,56 @@
private static final int REQUEST_PICK_CONTACT = 1;
private static final int REQUEST_CROP_PHOTO = 2;
- private static final String CONTACT_URI_KEY = "contact_uri";
+ private static final String RAW_CONTACT_URIS_KEY = "raw_contact_uris";
public AttachImage() {
}
- /**
- * Is the raw_contact uri for the contact the user selected
- */
- Uri mContactUri;
+ private Long[] rawContactIds;
+
+ private ContentResolver mContentResolver;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {
- mContactUri = icicle.getParcelable(CONTACT_URI_KEY);
+ rawContactIds = toClassArray(icicle.getLongArray(RAW_CONTACT_URIS_KEY));
} else {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(Contacts.CONTENT_ITEM_TYPE);
startActivityForResult(intent, REQUEST_PICK_CONTACT);
}
+
+ mContentResolver = getContentResolver();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- if (mContactUri != null) {
- outState.putParcelable(CONTACT_URI_KEY, mContactUri);
+ if (rawContactIds != null && rawContactIds.length != 0) {
+ outState.putLongArray(RAW_CONTACT_URIS_KEY, toPrimativeArray(rawContactIds));
}
}
+ private static long[] toPrimativeArray(Long[] in) {
+ long[] out = new long[in.length];
+ for (int i = 0; i < in.length; i++) {
+ out[i] = in[i];
+ }
+ return out;
+ }
+
+ private static Long[] toClassArray(long[] in) {
+ Long[] out = new Long[in.length];
+ for (int i = 0; i < in.length; i++) {
+ out[i] = in[i];
+ }
+ return out;
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
if (resultCode != RESULT_OK) {
@@ -98,17 +128,14 @@
// while they're cropping, convert the contact into a raw_contact
final long contactId = ContentUris.parseId(result.getData());
- final long rawContactId = ContactsUtils.queryForRawContactId(getContentResolver(),
- contactId);
+ final ArrayList<Long> rawContactIdsList = ContactsUtils.queryForAllRawContactIds(
+ mContentResolver, contactId);
+ rawContactIds = new Long[rawContactIdsList.size()];
+ rawContactIds = rawContactIdsList.toArray(rawContactIds);
- if (rawContactId == -1) {
+ if (rawContactIds == null || rawContactIdsList.isEmpty()) {
Toast.makeText(this, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
}
-
- mContactUri = Uri.withAppendedPath(
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
- RawContacts.Data.CONTENT_DIRECTORY);
-
} else if (requestCode == REQUEST_CROP_PHOTO) {
final Bundle extras = result.getExtras();
if (extras != null) {
@@ -118,13 +145,100 @@
photo.compress(Bitmap.CompressFormat.JPEG, 75, stream);
final ContentValues imageValues = new ContentValues();
- imageValues.put(Photo.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
imageValues.put(Photo.PHOTO, stream.toByteArray());
imageValues.put(RawContacts.Data.IS_SUPER_PRIMARY, 1);
- getContentResolver().insert(mContactUri, imageValues);
+
+ // attach the photo to every raw contact
+ for (Long rawContactId : rawContactIds) {
+
+ // exchange and google only allow one image, so do an update rather than insert
+ boolean shouldUpdate = false;
+
+ final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
+ rawContactId);
+ final Uri rawContactDataUri = Uri.withAppendedPath(rawContactUri,
+ RawContacts.Data.CONTENT_DIRECTORY);
+ insertPhoto(imageValues, rawContactDataUri, true);
+ }
}
}
finish();
}
}
+
+ /**
+ * Inserts a photo on the raw contact.
+ * @param values the photo values
+ * @param assertAccount if true, will check to verify if the account is Google or exchange,
+ * no photos exist (Google and exchange only take one picture)
+ */
+ private void insertPhoto(ContentValues values, Uri rawContactDataUri,
+ boolean assertAccount) {
+
+ ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>();
+
+ if (assertAccount) {
+ // make sure for Google and exchange, no pictures exist
+ operations.add(ContentProviderOperation.newAssertQuery(rawContactDataUri)
+ .withSelection(Photo.MIMETYPE + "=? AND "
+ + RawContacts.ACCOUNT_TYPE + " IN (?,?)",
+ new String[] {Photo.CONTENT_ITEM_TYPE, GoogleSource.ACCOUNT_TYPE,
+ ExchangeSource.ACCOUNT_TYPE})
+ .withExpectedCount(0).build());
+ }
+
+ // insert the photo
+ values.put(Photo.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
+ operations.add(ContentProviderOperation.newInsert(rawContactDataUri)
+ .withValues(values).build());
+
+ try {
+ mContentResolver.applyBatch(ContactsContract.AUTHORITY, operations);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Problem querying raw_contacts/data", e);
+ } catch (OperationApplicationException e) {
+ // the account doesn't allow multiple photos, so update
+ if (assertAccount) {
+ updatePhoto(values, rawContactDataUri, false);
+ } else {
+ throw new IllegalStateException("Problem inserting photo into raw_contacts/data", e);
+ }
+ }
+ }
+
+ /**
+ * Tries to update the photo on the raw_contact. If no photo exists, and allowInsert == true,
+ * then will try to {@link #updatePhoto(ContentValues, boolean)}
+ */
+ private void updatePhoto(ContentValues values, Uri rawContactDataUri,
+ boolean allowInsert) {
+ ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>();
+
+ values.remove(Photo.MIMETYPE);
+
+ // check that a photo exists
+ operations.add(ContentProviderOperation.newAssertQuery(rawContactDataUri)
+ .withSelection(Photo.MIMETYPE + "=?", new String[] {
+ Photo.CONTENT_ITEM_TYPE
+ }).withExpectedCount(1).build());
+
+ // update that photo
+ operations.add(ContentProviderOperation.newUpdate(rawContactDataUri).withSelection(Photo.MIMETYPE + "=?", new String[] {
+ Photo.CONTENT_ITEM_TYPE}).withValues(values).build());
+
+ try {
+ mContentResolver.applyBatch(ContactsContract.AUTHORITY, operations);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Problem querying raw_contacts/data", e);
+ } catch (OperationApplicationException e) {
+ if (allowInsert) {
+ // they deleted the photo between insert and update, so insert one
+ insertPhoto(values, rawContactDataUri, false);
+ } else {
+ throw new IllegalStateException("Problem inserting photo raw_contacts/data", e);
+ }
+ }
+ }
}
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 13a17c1..2a3c22d 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -17,46 +17,37 @@
package com.android.contacts;
-import com.android.contacts.model.ContactsSource;
-import com.android.contacts.ui.FastTrackWindow;
-import com.android.contacts.util.Constants;
-
-import java.io.ByteArrayInputStream;
-
-import android.provider.Contacts.People.Phones;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-
-import java.io.InputStream;
-
-import android.net.Uri;
import android.content.ContentResolver;
import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.Contacts;
import android.provider.Im.ProviderNames;
-import android.database.Cursor;
import android.text.TextUtils;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.util.Constants;
+
+import java.util.ArrayList;
+
public class ContactsUtils {
private static final String TAG = "ContactsUtils";
@@ -304,6 +295,26 @@
return rawContactId;
}
+ public static ArrayList<Long> queryForAllRawContactIds(ContentResolver cr, long contactId) {
+ Cursor rawContactIdCursor = null;
+ ArrayList<Long> rawContactIds = new ArrayList<Long>();
+ try {
+ rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
+ new String[] {RawContacts._ID},
+ RawContacts.CONTACT_ID + "=" + contactId, null, null);
+ if (rawContactIdCursor != null) {
+ while (rawContactIdCursor.moveToNext()) {
+ rawContactIds.add(rawContactIdCursor.getLong(0));
+ }
+ }
+ } finally {
+ if (rawContactIdCursor != null) {
+ rawContactIdCursor.close();
+ }
+ }
+ return rawContactIds;
+ }
+
/**
* Utility for creating a standard tab indicator view.