This line:

context.getContentResolver().update(ContactsContract.Data.CONTENT_URI,
values, ContactsContract.Data.RAW_CONTACT_ID + " = " + personId,
null);

attempts to change ALL data rows that have RAW_CONTACT_ID == personId, which
includes the photo, but also phone numbers, emails etc.  You will need to
find the specific row before updating it. The condition should say: Data._ID
+ "=" + dataId.  Alternatively, you can construct a specific URI:
ContentUris.withAppendedId(Data.CONTENT_URI, dataId)

I hope this helps.
- Dmitri

On Thu, Nov 5, 2009 at 9:05 AM, jarkman <jark...@gmail.com> wrote:

> Dmitri - I wasn't, but I am now - thanks for the tip.
>
> It doesn't fix the problem, though. It seems as though I can set the
> photo once on a brand-new contact, but I can never set it again on
> that contact.
>
> Do I perhaps need to do something with
> ContactsContract.Data.PHOTO_ID ?
>
> Here's code:
>
> ContentValues values = new ContentValues();
> values.put(ContactsContract.Data.RAW_CONTACT_ID, personId);
> values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
> values.put(ContactsContract.CommonDataKinds.Photo.PHOTO,
> bytes.toByteArray());
> values.put(ContactsContract.Data.MIMETYPE,
> ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE );
>
> context.getContentResolver().update(ContactsContract.Data.CONTENT_URI,
> values, ContactsContract.Data.RAW_CONTACT_ID + " = " + personId,
> null);
>
>
> And here's a stack:
>
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103): Writing exception to
> parcel
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):
> android.database.sqlite.SQLiteException: unknown error: Unable to
> convert BLOB to string
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> android.database.CursorWindow.getString_native(Native Method)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> android.database.CursorWindow.getString(CursorWindow.java:329)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> android.database.AbstractWindowedCursor.getString
> (AbstractWindowedCursor.java:49)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
>
> com.android.providers.contacts.ContactsProvider2$DataRowHandler.getAugmentedValues
> (ContactsProvider2.java:1038)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
>
> com.android.providers.contacts.ContactsProvider2$CommonDataRowHandler.update
> (ContactsProvider2.java:1225)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> com.android.providers.contacts.ContactsProvider2$PhoneDataRowHandler.update
> (ContactsProvider2.java:1445)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> com.android.providers.contacts.ContactsProvider2.updateData
> (ContactsProvider2.java:3091)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> com.android.providers.contacts.ContactsProvider2.updateData
> (ContactsProvider2.java:3075)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> com.android.providers.contacts.ContactsProvider2.updateInTransaction
> (ContactsProvider2.java:2854)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> com.android.providers.contacts.SQLiteContentProvider.update
> (SQLiteContentProvider.java:139)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> com.android.providers.contacts.ContactsProvider2.update
> (ContactsProvider2.java:1923)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> android.content.ContentProvider$Transport.update(ContentProvider.java:
> 180)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> android.content.ContentProviderNative.onTransact
> (ContentProviderNative.java:195)
> 11-05 17:03:36.781: ERROR/DatabaseUtils(103):     at
> android.os.Binder.execTransact(Binder.java:287)
>
>
> On Nov 5, 4:41 pm, Dmitri Plotnikov <dplotni...@google.com> wrote:
> > Hi Richard,
> >
> > Regarding photos: are you setting the IS_SUPER_PRIMARY flag on your Photo
> > row?  The notion of "super-primary" has to do with multiple accounts.
>  You
> > can have only one super-primary photo for an entire aggregated contact.
> >
> > Cheers,
> > - Dmitri
> >
> > On Thu, Nov 5, 2009 at 1:51 AM, jarkman <jark...@gmail.com> wrote:
> > > Jake - no, you are not the only one who suffers that frustration with
> > > the ContactsContract documentation.
> >
> > > I've spent a lot of time writing frankly experimental code because I
> > > couldn't work out from the docs how the various URIs and string
> > > constants had to be knitted together to actually work. I think the
> > > docs really need a lot more tiny examples, to make the context clear
> > > for each definition.
> >
> > > I still can't work out how to set contact photos reliably. I thought I
> > > had a fix yesterday, but it fails in some cases. Tiem for more
> > > experiments...
> >
> > > Richard
> >
> > > On Nov 5, 2:11 am, "jak." <koda...@gmail.com> wrote:
> > > > Thank you Dmitri,
> >
> > > > Your response was very helpful. Along with that, and the sample you
> > > > posted on another thread about using both Contact Apis from one app,
> > > > I've gotten most of the way there. It is much appreciated.
> >
> > > > I'm still however having some problems that I'm hard pressed to find
> a
> > > > solution for.
> > > > I'd be grateful if anyone could help me.
> >
> > > > The biggest challenge I'm  having with this API is that it's hard for
> > > > me to picture how the tables are laid out so I know which URI to
> query
> > > > to get the parts of the contact that I'm interested in.
> > > > I found to get the email address for a contact I'm looking at I can
> > > > query the uri:ContactsContract.CommonDataKinds.Email.CONTENT_URI,
> > > > looking at rows of the contact id i'm interested in.
> >
> > > > However to get the note from the same contact I can't use a similar
> > > > pattern, because there is no
> > > > ContactsContract.CommonDataKinds.Note.CONTENT_URI
> > > > The Note type exists in CommonDataKinds but it doesn't have an
> > > > associated CONTENT_URI.
> >
> > > > I'm finding it very frustrating to use this API because every time I
> > > > go to try to pull out another piece of data from the contact, the
> > > > method to access it seems to change (as I can't find a consistent way
> > > > to get a given field from a contact). And the documentation never
> > > > describes how these keys, tables, and URIs are related. Basically the
> > > > ContactsContract documentation just gives you a giant list of Objects
> > > > containing constants that describe indexes into some database that is
> > > > basically a black box without some basic documentation.
> >
> > > > I'm I the only one that finds this frustrating?
> >
> > > > Thanks again for your help.
> >
> > > > -Jake
> >
> > > > On Nov 2, 5:24 pm, Dmitri Plotnikov <dplotni...@google.com> wrote:
> >
> > > > > You can always delegate contact creation to the Contacts app using
> the
> > > > > ContactsContract.Intents.UI.Insert intent with extras. This will
> show
> > > the
> > > > > edit UI.
> >
> > > > > If you want to explicitly create the contact by yourself, that's
> now a
> > > bit
> > > > > tricky because Android 2.0 support multiple accounts.
> >
> > > > > First of all, you will need to figure out which account you want to
> > > create
> > > > > the contact in. Get a list of all available accounts from
> > > AccountManager:
> >
> > > > > AccountManager am = AccountManager.get(getContext());
> > > > > Account[] accounts = am.getAccounts();
> >
> > > > > Also, get a list of all sync adapters and find the ones that
> support
> > > > > contacts:
> >
> > > > > SyncAdapterType[] syncs
> > > > > = ContentResolver.getContentService().getSyncAdapterTypes();
> >
> > > > > for (SyncAdapterType sync : syncs) {
> > > > >      if (ContactsContract.AUTHORITY.equals(sync.authority) &&
> > > > > sync.supportsUploading()) {
> > > > >           contactAccountTypes.add(sync.accountType);
> > > > >      }
> >
> > > > > }
> >
> > > > > Now you have a list of all accounts and a list of account types
> that
> > > support
> > > > > contacts.  So here's your account list:
> >
> > > > > for (Account acct: accounts) {
> > > > >    if (contactAccountTypes.contains(acct.type)) {
> > > > >       contactAccounts.add(account);
> > > > >    }
> >
> > > > > }
> >
> > > > > If the contactAccounts list contains nothing - use accountType =
> null
> > > and
> > > > > accountName = null
> > > > > If it contains exactly one account, use it.
> > > > > If it contains multiple accounts, build a dialog and ask the user
> which
> > > > > account to use.
> >
> > > > > From here on it gets easier.
> >
> > > > > Let's start with a more traditional method.  Insert a raw contact
> > > first:
> >
> > > > > ContentValues values = new ContentValues();
> > > > > values.put(RawContacts.ACCOUNT_TYPE, accountType);
> > > > > values.put(RawContacts.ACCOUNT_NAME, accountName);
> > > > > Uri rawContactUri =
> > > getContentResolver().insert(RawContacts.CONTENT_URI,
> > > > > values);
> > > > > long rawContactId = ContentUris.parseId(rawContactUri);
> >
> > > > > Then insert the name:
> >
> > > > > values.clear();
> > > > > values.put(Data.RAW_CONTACT_ID, rawContactId);
> > > > > values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
> > > > > values.put(StructuredName.DISPLAY_NAME, "Some Body");
> > > > > getContentResolver().insert(Data.CONTENT_URI, values);
> >
> > > > > You are done.
> >
> > > > > Now here's a much better way to do the same.  Use the
> > > > > new ContentProviderOperation API, which will ensure that the raw
> > > contact and
> > > > > its name are inserted at the same time.
> >
> > > > > ArrayList<ContentProviderOperation> ops = Lists.newArrayList();
> > > > > ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
> > > > >         .withValue(RawContacts.ACCOUNT_TYPE, accountType)
> > > > >         .withValue(RawContacts.ACCOUNT_NAME, accountName)
> > > > >         .build());
> >
> > > > > ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
> > > > >         .withValueBackReference(Data.RAW_CONTACT_ID, 0)
> > > > >         .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
> > > > >         .withValue(StructuredName.DISPLAY_NAME, "Some Body")
> > > > >         .build());
> >
> > > > > getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
> >
> > > > > I hope this helps.
> > > > > - Dmitri
> >
> > > > > On Mon, Nov 2, 2009 at 4:23 PM, jak. <koda...@gmail.com> wrote:
> > > > > > Hello,
> >
> > > > > > I'm currently working on porting our Android app to 2.0 but I'm
> > > having
> > > > > > a rather hard time figuring out what is required to interact with
> the
> > > > > > new Contacts API.
> > > > > > I'm using reflection to decide whether the new API is available,
> if
> > > it
> > > > > > is I attempt to use the new features, otherwise I fall back to
> our
> > > old
> > > > > > methods.
> >
> > > > > > However, I'm having a hard time finding analogs to the old
> > > > > > functionality in the new API.
> > > > > > For example in the past I was adding contacts to the database
> from an
> > > > > > external text source by creating a ContentValues object, filling
> it
> > > > > > with information on the contact and then adding it with a call
> to:
> > > > > > Contacts.People.createPersonInMyContactsGroup(...);
> >
> > > > > > i.e.:
> > > > > > ...
> >
> > > > > > ContentValues personValues = new ContentValues();
> > > > > > personValues.put(Contacts.People.NAME, "Some Body");
> > > > > > Uri personUri = Contacts.People.createPersonInMyContactsGroup
> > > > > > (curContext().getContentResolver(), personValues);
> >
> > > > > > ...
> > > > > > How can I achieve the same goal in the new API?
> >
> > > > > > I appreciate all the hard work going into improving the APIs but
> I
> > > > > > must admit I'm a bit frustrated by the lack of documentation and
> > > > > > examples.
> > > > > > I realize we have plenty of Javadocs on developer.android.com to
> > > > > > reference, but those only really show us what the new interfaces
> are.
> > > > > > I'm having a really hard time finding any discussion in terms of
> how
> > > > > > the new API is intended to be used.
> >
> > > > > > Any help would be greatly appreciated!
> > > > > > Thanks!
> >
> > > > > > --
> > > > > > You received this message because you are subscribed to the
> Google
> > > > > > Groups "Android Developers" group.
> > > > > > To post to this group, send email to
> > > android-developers@googlegroups.com
> > > > > > To unsubscribe from this group, send email to
> > > > > > android-developers+unsubscr...@googlegroups.com<android-developers%2bunsubscr...@googlegroups.com>
> <android-developers%2bunsubscr...@googlegroups.com<android-developers%252bunsubscr...@googlegroups.com>
> ><android-developers%2Bunsubs
> > > cr...@googlegroups.com>
> > > > > > For more options, visit this group at
> > > > > >http://groups.google.com/group/android-developers?hl=en
> >
> > > --
> > > You received this message because you are subscribed to the Google
> > > Groups "Android Developers" group.
> > > To post to this group, send email to
> android-developers@googlegroups.com
> > > To unsubscribe from this group, send email to
> > > android-developers+unsubscr...@googlegroups.com<android-developers%2bunsubscr...@googlegroups.com>
> <android-developers%2bunsubscr...@googlegroups.com<android-developers%252bunsubscr...@googlegroups.com>
> >
> > > For more options, visit this group at
> > >http://groups.google.com/group/android-developers?hl=en
> >
> >
>
> --
> You received this message because you are subscribed to the Google
> Groups "Android Developers" group.
> To post to this group, send email to android-developers@googlegroups.com
> To unsubscribe from this group, send email to
> android-developers+unsubscr...@googlegroups.com<android-developers%2bunsubscr...@googlegroups.com>
> For more options, visit this group at
> http://groups.google.com/group/android-developers?hl=en
>

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to