# Get set remove full-sized and thumbnail contact photos This library provides several functions to interact with Contact and RawContact full-sized and thumbnail photos. > ⚠️ The APIs for this have changed significantly since [version 0.3.0](https://github.com/vestrel00/contacts-android/releases/tag/0.3.0). > For documentation for [version 0.2.4](https://github.com/vestrel00/contacts-android/releases/tag/0.2.4) > and below, [visit this page (click me)](https://github.com/vestrel00/contacts-android/blob/0.2.4/docs/other/get-set-remove-contact-raw-contact-photo.md). ## Contact and RawContact photos The photo assigned to a Contact is just a reference to a photo assigned to a RawContact. If a Contact consists of more than one RawContact, only the photo from one of the RawContacts will be used by the Contact. Setting/removing the (main) RawContact's photo will in turn change the Contact photo because the Contact photo is just a reference to the RawContact photo. The inverse is also true. RawContact photos are retained when linking and unlinking. > ℹ️ For more info, read [Link unlink Contacts](./../other/link-unlink-contacts.md). ## Full-sized photos and thumbnails Each RawContact may be assigned one photo. The thumbnail is just a downsized version of the full-sized photo. The full-sized photo is typically displayed in a large view, such as in a contact detail screen. The thumbnail is typically displayed in small views, such as in a contacts list view. Setting the full-sized photo will automatically set the thumbnail. The Contacts Provider automatically creates a downsized version of the full-sized photo. ## Getting contact photo There are several ways to do this. Using query APIs to get a list of `Contact`s with photo uris, ```kotlin val contacts = Contacts(context) .query() // if you only want to include photo data in the returned Contacts .include( Fields.Contact.PhotoUri, Fields.Contact.PhotoThumbnailUri ) .find() for (contact in contacts) { Log.d( "Contact", """ Photo Uri: ${contact.photoUri} Thumbnail Uri: ${contact.photoThumbnailUri} """.trimIndent() ) } ``` > ℹ️ For more info, read [Query contacts](./../basics/query-contacts.md) > and [Query contacts (advanced)](./../basics/query-contacts-advanced.md). Using one of the extension functions in `contacts.core.util.ContactPhoto.kt` to get photo data, ```kotlin val photoInputStream = contact.photoInputStream(contactsApi) val photoBytes = contact.photoBytes(contactsApi) val photoBitmap = contact.photoBitmap(contactsApi) val photoBitmapDrawable = contact.photoBitmapDrawable(contactsApi) val photoThumbnailInputStream = contact.photoThumbnailInputStream(contactsApi) val photoThumbnailBytes = contact.photoThumbnailBytes(contactsApi) val photoThumbnailBitmap = contact.photoThumbnailBitmap(contactsApi) val photoThumbnailBitmapDrawable = contact.photoThumbnailBitmapDrawable(contactsApi) ``` To get RawContact photos directly, use one of the extension functions in `contacts.core.util.RawContactPhoto.kt`, ```kotlin val photoInputStream = rawContact.photoInputStream(contactsApi) val photoBytes = rawContact.photoBytes(contactsApi) val photoBitmap = rawContact.photoBitmap(contactsApi) val photoBitmapDrawable = rawContact.photoBitmapDrawable(contactsApi) val photoThumbnailInputStream = rawContact.photoThumbnailInputStream(contactsApi) val photoThumbnailBytes = rawContact.photoThumbnailBytes(contactsApi) val photoThumbnailBitmap = rawContact.photoThumbnailBitmap(contactsApi) val photoThumbnailBitmapDrawable = rawContact.photoThumbnailBitmapDrawable(contactsApi) ``` > ℹ️ The Contact photo is just a reference to one of its RawContact's photo. ## Setting contact photo There are two ways to set Contact or RawContact photo. > ⚠️ Make sure that the Contact instances you are performing these operations on came from a query > that included all fields from `Fields.PrimaryPhotoHolder`. Otherwise, the incorrect child > RawContact's photo may be set (in case the Contact has more than one child RawContact). ### Using extension functions This can only be done for existing Contacts/RawContacts. To set the Contact photo, use one of the extension functions in `contacts.core.util.ContactPhoto.kt`, ```kotlin contact.setPhotoDirect(contactsApi, PhotoData.from(inputStream)) contact.setPhotoDirect(contactsApi, PhotoData.from(byteArray)) contact.setPhotoDirect(contactsApi, PhotoData.from(bitmap)) contact.setPhotoDirect(contactsApi, PhotoData.from(bitmapDrawable)) ``` Setting the full-sized photo will automatically set the thumbnail. The Contacts Provider automatically creates a downsized version of the full-sized photo. To set a RawContact photo, use one of the extension functions in `contacts.core.util.RawContactPhoto.kt`, ```kotlin rawContact.setPhotoDirect(contactsApi, PhotoData.from(inputStream)) rawContact.setPhotoDirect(contactsApi, PhotoData.from(byteArray)) rawContact.setPhotoDirect(contactsApi, PhotoData.from(bitmap)) rawContact.setPhotoDirect(contactsApi, PhotoData.from(bitmapDrawable)) ``` > ℹ️ Prior to [version 0.3.0](https://github.com/vestrel00/contacts-android/releases/tag/0.3.0), these > functions were named `setPhoto`. ### As part of an insert or update API call > ℹ️ Setting photo as part of insert or update API calls was not possible prior to > [version 0.3.0](https://github.com/vestrel00/contacts-android/releases/tag/0.3.0). To insert a new RawContact with a photo, ```kotlin Contacts(this) .insert() .rawContact { setPhoto(PhotoData.from(...)) } .commit() ``` > ℹ️ For more info on insert APIs, read [Insert contacts](../basics/insert-contacts.md). To update an existing Contact or RawContact with a photo, ```kotlin Contacts(this) .update() .contacts( contact.mutableCopy { setPhoto(PhotoData.from(...)) } ) .rawContacts( rawContact.mutableCopy { setPhoto(PhotoData.from(...)) } ) .commit() ``` > ℹ️ For more info on update APIs, read [Update contacts](../basics/update-contacts.md). ## Removing contact photo There are two ways to remove Contact or RawContact photo. > ⚠️ Make sure that the Contact instances you are performing these operations on came from a query > that included all fields from `Fields.PrimaryPhotoHolder`. Otherwise, the incorrect child > RawContact's photo may be removed (in case the Contact has more than one child RawContact). ### Using extension functions This can only be done for existing Contacts/RawContacts. To remove the Contact (and corresponding RawContact) photo (full-sized and thumbnail), ```kotlin contact.removePhotoDirect(contactsApi) ``` To remove a specific RawContact's photo (full-sized and thumbnail), ```kotlin rawContact.removePhotoDirect(contactsApi) ``` > ℹ️ Prior to [version 0.3.0](https://github.com/vestrel00/contacts-android/releases/tag/0.3.0), > these functions were named `removePhoto`. ### As part of an update API call > ℹ️ Removing photo as part of insert or update API calls was not possible prior to > [version 0.3.0](https://github.com/vestrel00/contacts-android/releases/tag/0.3.0). To update an existing Contact or RawContact without a photo, ```kotlin Contacts(this) .update() .contacts( contact.mutableCopy { removePhoto() } ) .rawContacts( rawContact.mutableCopy { removePhoto() } ) .commit() ``` > ℹ️ For more info on update APIs, read [Update contacts](../basics/update-contacts.md). ## Using the ui PhotoPicker extensions The `contacts.ui.util.PhotoPicker.kt` in the `ui` module` provides extension functions to make selecting existing photos, taking new photos, and removing photos easier. It provides you the same UX as the AOSP Contacts app. To use it, ```kotlin Activity { fun onPhotoViewClicked() { showPhotoPickerDialog( withRemovePhotoOption = true, removePhoto = { // remove contact photo } ) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) onPhotoPicked(requestCode, resultCode, data, photoBitmapPicked = { photoBitmap -> // set contact photo }, photoUriPicked = { uri -> // Note that bitmap decoding should be done in a non-UI thread. Threading has been // left out of this example for brevity. val photoBitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, uri)) } else { MediaStore.Images.Media.getBitmap(context.contentResolver, uri) } // set contact photo } ) } } ``` Starting with Android 11 (API 30), you must include the following to your manifest in order to successfully use the above functions. ``` <queries> <intent> <action android:name="android.media.action.IMAGE_CAPTURE" /> </intent> <intent> <action android:name="android.intent.action.PICK" /> </intent> </queries> ``` ## Performing photo management asynchronously All of the code shown in this guide are done in the same thread as the call-site. This may result in a choppy UI. To perform the work in a different thread, use the Kotlin coroutine extensions provided in the `async` module. For more info, read [Execute work outside of the UI thread using coroutines](./../async/async-execution-coroutines.md). You may, of course, use other multi-threading libraries or just do it yourself =) > ℹ️ Extensions for Kotlin Flow and RxJava are also in the project roadmap. ## Performing photo management with permission Getting and setting photos require the `android.permission.READ_CONTACTS` and `android.permission.WRITE_CONTACTS` permissions respectively. If not granted, getting/setting photos will fail. To perform the get/set photo with permission, use the extensions provided in the `permissions` module. For more info, read [Permissions handling using coroutines](./../permissions/permissions-handling-coroutines.md). You may, of course, use other permission handling libraries or just do it yourself =)