Insert Contact (ContactsContract) via Intent with Image (Photo)
Asked Answered
J

4

13

There is many Q&A threads, but none of them is providing real answer, or I couldn't find it.

To ensure you, I've searched before asking:

So is there anyone, who knows how to use Intent (as in example code) and insert a Photo, which is held in Bitmap ?

Example code I do use now to start dialog intent for user to let him insert or cancel and possibly edit fields before saving:

// PrivateContactClass c;
// Bitmap photo;
Intent inOrUp = new Intent(ContactsContract.Intents.Insert.ACTION, ContactsContract.Contacts.CONTENT_URI);
inOrUp.setType(ContactsContract.Contacts.CONTENT_TYPE);
inOrUp.putExtra(ContactsContract.Intents.Insert.NAME, ModelUtils.formatName(c));
inOrUp.putExtra(ContactsContract.Intents.Insert.PHONE, getPrimaryPhone());
inOrUp.putExtra(ContactsContract.Intents.Insert.TERTIARY_PHONE, c.getMobile());
inOrUp.putExtra(ContactsContract.Intents.Insert.EMAIL, c.getMail());
inOrUp.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, c.getFunction());
inOrUp.putExtra(ContactsContract.Intents.Insert.NOTES, getSummary());
inOrUp.putExtra(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
startActivity(inOrUp);

I have found a solution, thanks to Julien's answer

Not using only intent, as I doubt that we can pass ID of image saved by Data ContentProvider, or pass Bitmap directly within Intent.

Extends from code above

Use startActivityForResult with constant request code

// must be declared in class-context
private static final int CONTACT_SAVE_INTENT_REQUEST = 1;
...
startActivityForResult(inOrUp,CONTACT_SAVE_INTENT_REQUEST);

Add handling result from activity started by Intent

@Override
protected void onActivityResult(int requestCode, int resultCode,
        Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    switch (requestCode) {
    case RESULT_INSERT_CONTACT:
        if (resultCode == RESULT_OK) {
            trySetPhoto();
        }
        break;
    }
}

Add Method to set photo

public boolean setDisplayPhotoByRawContactId(long rawContactId, Bitmap bmp) {
     ByteArrayOutputStream stream = new ByteArrayOutputStream();
     bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
     byte[] byteArray = stream.toByteArray();
     Uri pictureUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, 
             rawContactId), RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
     try {
         AssetFileDescriptor afd = getContentResolver().openAssetFileDescriptor(pictureUri, "rw");
         OutputStream os = afd.createOutputStream();
         os.write(byteArray);
         os.close();
         afd.close();
         return true;
     } catch (IOException e) {
         e.printStackTrace();
     }
     return false;
 }

Add Method to search for contacts and add contact photos

private void trySetPhoto() {
    // Everything is covered in try-catch, as this method can fail on 
    // low-memory or few NPE
    try {
        // We must have an phone identifier by which we search for
        // format of phone number is not relevant, as ContentProvider will
        // normalize it automatically
        if (c.getMobile() != null) {
            Uri lookup = Uri.withAppendedPath(
                    ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
                    Uri.encode(c.getMobile()));
            Cursor c = getContentResolver().query(lookup, null, null, null,
                    null);
            // Remember cursor can be null in some cases
            if (c != null) {
                // we can obtain bitmap just once
                Bitmap photo_bitmap = getPhotoBitmap();
                c.moveToFirst();
                // if there are multiple raw contacts, we want to set the photo for all of them
                while (c.moveToNext()) {
                    setDisplayPhotoByRawContactId(
                            c.getLong(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID)),
                            photo_bitmap);
                }
                // remember to clean up after using cursor
                c.close();
            }
        }
    } catch (Exception e) {
        // Logging procedures
    } catch (Error e) {
        // Logging procedures
    }
}
Jacquiline answered 22/2, 2013 at 14:22 Comment(3)
Accepted answer now doesn't use Intent only to set Contacts photo, so I will wait with granting bounty reward, if anybody has answer using Intent only :-)Jacquiline
Your solution unfortunately does not work for me. The phone-lookup uri does not return a cursor that has RAW_CONTACT_ID.Atomic
Another issue is that the intent does not return a RESULT_OK after creating the contact. At least on my Nexus 5 I get a "Create contact" screen, but if I press finish to save the contact I am shown the created contact. To get back to my app I have to press the back button witch gives RESULT_CANCELED, the same as if I had aborted the creation process. If I press home or just not return to the app the image-adding process is not happening at all, so this is only a "maybe way" to add a picture, even if I could get it to work.Atomic
C
14
Bitmap bit = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); // your image

ArrayList<ContentValues> data = new ArrayList<ContentValues>();

ContentValues row = new ContentValues();
row.put(Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
row.put(ContactsContract.CommonDataKinds.Photo.PHOTO, bitmapToByteArray(bit));
data.add(row);

Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
intent.putParcelableArrayListExtra(Insert.DATA, data);
Claret answered 29/5, 2013 at 1:13 Comment(3)
This is what i needed. But somehow i don't see the photo being inserted.Dumah
Should be the correct answer, also works for me and seems to be best solutionRyanryann
This works for me too. More documentation here: developer.android.com/reference/android/provider/…Cadet
D
4

to help you, i found original documentation: http://java.llp2.dcc.ufmg.br/apiminer/docs/reference/android/provider/ContactsContract.RawContacts.DisplayPhoto.html

and read this: http://java.llp2.dcc.ufmg.br/apiminer/docs/reference/android/provider/ContactsContract.RawContacts.html

for me, a simple solution would be if your code works call:

startActivityForResult(inOrUp, CODE_INSERT_CONTACT);

Then in "onActivityResult" call "setDisplayPhotoByRawContactId.":

    /** @return true if picture was changed false otherwise. */
public boolean setDisplayPhotoByRawContactId(long rawContactId, Bitmap bmp) {
     ByteArrayOutputStream stream = new ByteArrayOutputStream();
     bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
     byte[] byteArray = stream.toByteArray();
     Uri pictureUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, 
             rawContactId), RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
     try {
         AssetFileDescriptor afd = getContentResolver().openAssetFileDescriptor(pictureUri, "rw");
         OutputStream os = afd.createOutputStream();
         os.write(byteArray);
         os.close();
         afd.close();
         return true;
     } catch (IOException e) {
         e.printStackTrace();
     }
     return false;
 }

Normally, this code works from version 14 of the API. I had to do research on this topic.

You can get rawContactId as indicated in the documentation:

Uri rawContactUri = RawContacts.URI.buildUpon()
      .appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName)
      .appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType)
      .build();
long rawContactId = ContentUris.parseId(rawContactUri);

I'm not sure but the documentation will help you. Sorry for my english.

Drier answered 26/2, 2013 at 9:25 Comment(2)
merge please your answers, I'll try this today, and give you some feedback asapJacquiline
for me i have a problem with RawContacts.URI, URI is not found... if you too, we must find another way to retrieve rawContactUri or rawContactId.Drier
R
2

This is the same answer as yeo100, but in Kotlin.

//Create Intent - I use ACTION_INSERT_OR_EDIT but you could use ACTION_INSERT
val intent = Intent(Intent.ACTION_INSERT_OR_EDIT).apply {
   type = ContactsContract.Contacts.CONTENT_ITEM_TYPE
}

intent.apply {

   //Add name, phone numbers, etc
   putExtra(ContactsContract.Intents.Insert.NAME, "John Smith")

   ...

   /*
   Start Adding Contact's Photo
   */

   //Get photo from an imageView into a byteArray
   var imageAsBitmap = (myImageView.drawable as BitmapDrawable).bitmap
   val stream = ByteArrayOutputStream()
   imageAsBitmap.compress(Bitmap.CompressFormat.PNG, 90, stream)
   val imageData = stream.toByteArray()

   //Add image data to an Array of ContentValues
   val data = ArrayList<ContentValues>()
   val row = ContentValues()
   row.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
   row.put(ContactsContract.CommonDataKinds.Photo.PHOTO, imageData)
   data.add(photoRow)

   //Add array to your Intent as data
   putExtra(ContactsContract.Intents.Insert.DATA, data)
}

startActivity(intent)
Reber answered 23/5, 2020 at 4:15 Comment(0)
S
1

The accepted answer does not do what the question asked.

Please refer to @yeo100's answer which uses the ContactsContract.Intents.Insert.DATA (docs - somewhat obscure and hard to find :/), as contact photos are saved in the Data table under a specific mimetype:

Data.MIMETYPE -> ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE

That worked for me, and is much neater and easier to manage.

Sitzmark answered 9/6, 2014 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.