How to get bitmap Contact photo uri - android

When converting the content://com.android.contacts/display_photo/4 to bitmap getting this error
Failed to create image decoder with message 'unimplemented'
I need the user photo image which he used in the contact or default image
Below is the code
private fun getContactNumbers(): ArrayList<ArrayList<String>> {
val contactsNumberMap = ArrayList<ArrayList<String>>()
val phoneCursor: Cursor? = context.contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null,
null,
null
)
if (phoneCursor != null && phoneCursor.count > 0) {
val numberIndex =
phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val nameIndex =
phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val photoIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_URI)
while (phoneCursor.moveToNext()) {
val number: String = phoneCursor.getString(numberIndex)
val name: String = phoneCursor.getString(nameIndex)
val uri: String = phoneCursor.getString(photoIndex)
//check if the map contains key or not, if not then create a new array list with number
val objectNameNumber = ArrayList<String>()
objectNameNumber.add(name);
objectNameNumber.add(number)
if(uri.isNotEmpty()) {
val input: InputStream =
applicationContext.contentResolver.openInputStream(Uri.parse(uri))!!
BitmapFactory.decodeStream(input)
println(uri)
println(BitmapFactory.decodeStream(input))
println("ByteArray-photo_stream")
}
if (!contactsNumberMap.contains(objectNameNumber)) {
contactsNumberMap.add(objectNameNumber);
}
}
//contact contains all the number of a particular contact
phoneCursor.close()
}
return contactsNumberMap
}

Use a different image decoder. If the current decoder is unable to handle the image data at the specified URI, you can try using a different decoder. For example, you can try using the Glide or Picasso libraries to load the image.
Based on the code you provided, it seems that you're trying to load contact photos from the PHOTO_URI column of the ContactsContract.CommonDataKinds.Phone table. Here's code that shows how to load the contact photo using Glide library:
private fun getContactNumbers(): ArrayList<ArrayList> {
val contactsNumberMap = ArrayList<ArrayList>()
val phoneCursor: Cursor? = context.contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null,
null,
null
)
if (phoneCursor != null && phoneCursor.count > 0) {
val numberIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val nameIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val photoIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_URI)
while (phoneCursor.moveToNext()) {
val number: String = phoneCursor.getString(numberIndex)
val name: String = phoneCursor.getString(nameIndex)
val uri: String = phoneCursor.getString(photoIndex)
val objectNameNumber = ArrayList<String>()
objectNameNumber.add(name)
objectNameNumber.add(number)
if (!uri.isNullOrEmpty()) {
// Load the contact photo using Glide
val photoBitmap = Glide.with(context)
.asBitmap()
.load(uri)
.submit()
.get()
if (photoBitmap != null) {
// do something with the photoBitmap
}
}
if (!contactsNumberMap.contains(objectNameNumber)) {
contactsNumberMap.add(objectNameNumber);
}
}
phoneCursor.close()
}
return contactsNumberMap
}
This code uses the Glide library to load the contact photo and get a Bitmap representation of it. If the photo is not available or if there is an error loading it, photoBitmap will be null. You can then use the photoBitmap object to display or process the contact photo.

Related

Android 12 crop image get SecurityExectipion

I'm trying to crop media images from MediaStore query,but got this Execption:
Caused by: java.lang.SecurityException: UID 10160 does not have permission to content://media/external/images/media/48 [user 0]
at android.os.Parcel.createExceptionOrNull(Parcel.java:2425)
at android.os.Parcel.createException(Parcel.java:2409)
at android.os.Parcel.readException(Parcel.java:2392)
at android.os.Parcel.readException(Parcel.java:2334)
at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2326)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1758)
at android.app.Activity.startActivityForResult(Activity.java:5407)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:588)
at android.app.Activity.startActivityForResult(Activity.java:5365)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:574)
As I completely understand it's permission related problem, yet I have no idea how to fix it.As far as I can see,the Crop-App has no read permission to [content://media/external/images/media/48],which my-own-app hold.
the code cause this problem as below:
val su = srcUri ?: throw IllegalArgumentException("Source uri is Null")
val f = if (path.isNullOrBlank()) {
File(
FileTool.getAppCacheDir(act),
tempCropName()
).also { path = it.absolutePath }
} else {
File(path!!)
}
val cropUri =
FileTool.getFileUri(act, f) ?: throw IllegalArgumentException("Failed to get crop uri")
val intent = Intent("com.android.camera.action.CROP").also {
it.setDataAndType(su, MediaType.IMAGE.value())
it.putExtra("aspectX", 1)//ratio
it.putExtra("aspectY", 1)
it.putExtra("outputX", size)//size
it.putExtra("outputY", size)
it.putExtra("scale", true)
it.putExtra("return-data", false)//no thumbnail got from back intent
it.putExtra("outputFormat", format)
it.putExtra(MediaStore.EXTRA_OUTPUT, cropUri)
}
and the SecurityException located at it.setDataAndType(su, MediaType.IMAGE.value()).
as for su,the source uri,got like this
private fun loadImageUriList(
bucketId: Long,
context:Context
): List<Uri>? {
val selection = "${MediaStore.Images.Media.BUCKET_ID} = ?"
val sort = "${MediaStore.Images.Media._ID} DESC"
val selectionArgs = arrayOf(bucketId.toString())
val images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val c = context.contentResolver.query(images, null, selection, selectionArgs, sort)?:return null
val imageUris = arrayListOf<Uri>()
try {
if (c.moveToFirst()) {
val iid = c.getColumnIndex(MediaStore.MediaColumns._ID)
do {
val imgId = c.getInt(iid)
val path = Uri.withAppendedPath(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imgId.toString()
)
imageUris.add(path)
} while (c.moveToNext())
}
} finally {
c.closeQuietly()
}
return imageUris
}
)
I tried
MediaStore.getRedactedUri(resolver,su)
but the problem still ocurred.
by the way, crop image from the system camera worked fine.
Now,I have to copy the image from source Uri to my app's directory,then do the crop job(the Intent above).it's so much work to do and ugly,I know I must have missed something,but I look through google developer doc,got nothing.
please ,help.

How to rename image from gallery and save it?

I use this function to show images from specific album in gallery:
fun findImagesInAlbum(albumId: String): List<Image> {
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projections = arrayOf(
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.DISPLAY_NAME
)
val selection = "${MediaStore.Images.ImageColumns.BUCKET_ID} == ?"
val selectionArgs = arrayOf(albumId)
val findImages = HashMap<String, Image>()
contentResolver.query(contentUri, projections, selection, selectionArgs,
"${MediaStore.Images.ImageColumns.DATE_TAKEN} ASC")?.use { cursor ->
if (cursor.moveToFirst()) {
val idIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID)
val displayNameIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DISPLAY_NAME)
do {
val mediaId = cursor.getLong(idIndex)
val filename = cursor.getString(displayNameIndex)
val uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
mediaId
)
val image = Image(
id = mediaId.toString(),
name = filename,
uri = uri,
count = 0,
)
findImages[mediaId.toString()] = image
image.count++
} while (cursor.moveToNext())
}
}
return findImages.values.toList().sortedByDescending { it.name }
}
I show the List<Image> at the RecyclerView and it works fine. After clicking on image it opens on fullscreen. What functions can i use to rename an opened image and save its name in the phone storage?
I tried to solve this problem with DocumentsContract.renameDocument, but it throws error: java.lang.UnsupportedOperationException: Unsupported call: android:renameDocument.

The most efficient way of reading Exif (LatLng) for gallery images

I want to get GPS coordinates of all the images in the user gallery. The solution below works, but it takes 15 seconds for 1500 photos in the gallery. Is there a more efficient way? The result shall be an array of all user photos and their locations.
Loading all images (600ms for 1500 photos):
resolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)?.use { cursor ->
Getting Exif data for each (15s for 1500 photos):
fun readExif(resolver: ContentResolver, id: Long): String? {
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id,
)
var photoUri = MediaStore.setRequireOriginal(contentUri)
var a: String? = ""
var b: String? = ""
var c: String? = ""
resolver.openInputStream(photoUri)?.use { stream ->
val exifInterface = ExifInterface(stream);
a = exifInterface.getAttribute(ExifInterface.TAG_DATETIME)
b = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE)
c = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE)
}
return a;
}

MEDIASTORE images, got nothing

I added the request premissions for reading files tried this method inside my activity but nothing shows,like there is no images in real devices and emulator,what am i doing wrong?
fun storaheread() {
val imageProjection = arrayOf(
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media._ID
)
val imageSortOrder = "${MediaStore.Images.Media.DATE_TAKEN} DESC"
val cursor = contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
imageProjection,
null,
null,
imageSortOrder
)
cursor.use {
it?.let {
val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val nameColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
val sizeColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)
val dateColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN)
while (it.moveToNext()) {
val id = it.getLong(idColumn)
val name = it.getString(nameColumn)
val size = it.getString(sizeColumn)
val date = it.getString(dateColumn)
val contentUri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id
)
// add the URI to the list
// generate the thumbnail
// val thumbnail = (this as Context).contentResolver.loadThumbnail(contentUri, Size(480, 480), null)
Log.d("image name",name)
}
} ?: kotlin.run {
Log.e("TAG", "Cursor is null!")
}
}
}
you can check out this similar question, it may help you achieve this situation.
Loading all the images from gallery into the Application in android

How to get images from phone on API below 29

I develop image gallery app for Android (min sdk 23, target sdk 29). And I trying to get list of photos from the phone. Here the code:
val list: MutableList<Photo> = mutableListOf()
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.ORIENTATION,
MediaStore.Images.Media.SIZE
)
val query = contentResolver?.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
MediaStore.Images.Media.DATE_TAKEN + " DESC"
)
query?.use { cursor ->
if (cursor.count != 0) {
val idIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val sizeIndex = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
while (cursor.moveToNext()) {
val id = cursor.getLong(idIndex)
val size = cursor.getInt(sizeIndex)
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id
)
val photo = Photo(contentUri, size)
list.add(photo)
}
}
}
But Android Studio says to me that some MediaStore fields requires API level 29+. (e.g. MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.ORIENTATION, MediaStore.Images.Media.DATA, etc.).
Screen from AS.
So my question is how do I should get images list on APIs below 29?
Also studio says same about contentResolver.loadThumbnail() method.
And adjacent question: is it possible in Android to retrieve list of photo albums? Or I should get list of all images and then run over it and pick out albums?
Try this, it's work even with API 29 :
private fun getAllImages(activity: Activity): ArrayList<Photo>? {
var cursor: Cursor? = null
var i = 0
val arrayList: ArrayList<Photo> = ArrayList()
if (cursor == null) {
val resolver = activity.contentResolver
cursor = resolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
null,
null,
null
)
if (cursor != null) {
while (i < cursor.count) {
cursor.moveToPosition(i)
val fieldIndex: Int = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val id: Long = cursor.getLong(fieldIndex)
val imageUri =
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
arrayList.add(Photo("", imageUri))
i++
}
cursor.close()
}
}
return arrayList
}
data class Photo(var name: String, var uri: Uri)
Use any image loader library such as Glide or Picasso :
Glide.with(this).load(getAllImages(this)!![0].uri).into(imgView)
Add this permission to your manifest, and make sure it granted :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Categories

Resources