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