Retrieve photo from contact android - java

I used this code to retrieve a photo from one contact:
private Uri getPhotoUri(String idContact) {
try {
Cursor cur = getApplicationContext().getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID + "=" + idContact + " AND "
+ ContactsContract.Data.MIMETYPE + "='"
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'", null,
null);
if (cur != null) {
if (!cur.moveToFirst()) {
return null; // no photo
}
} else {
return null; // error in cursor process
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long
.parseLong(idContact));
return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
}
So, the problem is that with this code I can retrieve a photo with low resolution.
How can i do to get a better photo?
Maybe I am not supposed to use CONTENT_DIRECTORY.
Thank you.

This code works pretty well to get a high-res photo:
Uri my_contact_Uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(id));
InputStream photo_stream = ContactsContract.Contacts.openContactPhotoInputStream(cr, my_contact_Uri, true);
BufferedInputStream buf = new BufferedInputStream(photo_stream);
Bitmap my_btmp = BitmapFactory.decodeStream(buf);
buf.close();
return my_btmp;
Also, just fyi, high-res contact photos didn't exist before API 14, so if you're running it on a AVD/Device with API 13 or less, you can't get a high-res photo.
Look at this question: Get high-res contact photo as bitmap below API level 14 Android for more info.

Related

Access the last image in user's gallery and show it in ImageView without selecting

I want to show the last image from user's gallery and show it in the ImageView. I used below code but got no success after all.
private void getLastGalleryImage() {
// Find the last picture
String[] projection = new String[]{
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.MIME_TYPE
};
final Cursor cursor = this.getContentResolver()
.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null,
null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
// Put it in the image view
if (cursor != null) {
if (cursor.moveToFirst()) {
String imageLocation = cursor.getString(1);
File imageFile = new File(imageLocation);
if (imageFile.exists()) {
Bitmap bm = BitmapFactory.decodeFile(imageLocation);
galleryImageView.setImageBitmap(bm);
}
}
}
}
What I want to achieve is shown in the image below:
Your code to obtain a bitmap instance is wrong (as it is useless for Android 10 and 11) where you use the File class.
Better use ._ID column to construct the uri for the file and then use the two code lines mentioned in: Android 10 MediaStore file permission

onPostExecute is called twice and showing double result

I am trying to download some files in background, for that I used download manager and I made this method:
/*** media download ***/
public long mediaDownload(ArrayList<DownloadedFile> arrayList, String foldPathName) {
long downloadReference = 0;
// Create request for android download manager
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
for (int i = 0; i < arrayList.size();i++){
DownloadManager.Request request = new DownloadManager.Request(arrayList.get(i).getUri());
request.setTitle("Data Download");
request.setDescription("New media");
//Set the local destination for the downloaded file to a path
//within the application's external files directory
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS + "/" + folder_main + "/" + foldPathName, arrayList.get(i).getName());
File f = new File(Environment.DIRECTORY_DOWNLOADS + "/" + folder_main + "/" + foldPathName + "/" + arrayList.get(i).getName());
Log.e("File:",f.toString());
//Enqueue download and save into referenceId
downloadReference = downloadManager.enqueue(request);
}
return downloadReference;
}
I have a picture and a Video to download for test, and when checking downloaded file in Explorer I find 2 videos and 2 picture, debug that I found that onPostExecute method is called twice and I can't figure out why.
Here is my onPostExecute method:
protected void onPostExecute(String s) {
try {
JSONObject jsonObject = new JSONObject(s);
JSONArray region = null;
region = jsonObject.getJSONArray("regions");
Log.e("Regions:", String.valueOf(region.length()));
for (int i = 0; i < region.length(); i++) {
try {
JSONObject json_data = region.getJSONObject(i);
int height_view = Integer.parseInt(json_data.getString("height"));
int width_view = Integer.parseInt(json_data.getString("width"));
int left_view = Integer.parseInt(json_data.getString("left"));
int top_view = Integer.parseInt(json_data.getString("top"));
int right_view = Integer.parseInt(json_data.getString("right"));
int bottom_view = Integer.parseInt(json_data.getString("bottom"));
/**** Media in region ***/
JSONObject media = json_data.getJSONObject("media");
String type_media = media.getString("type");
url = media.getString("url");
name = media.getString("name");
uri = Uri.parse(url);
} catch (JSONException e) {
e.printStackTrace();
}
downloadedFiles.add(new DownloadedFile(name, uri));
}
Toast.makeText(MainActivity.this, "Layout Created with" + height + "x" + width, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("Downloaded Files:",downloadedFiles.toString());
mediaDownload(downloadedFiles, folderName); // region media's download
}
On my logcat I see that my arrayList has 2 elements, but displayed twice, which means files are downloaded twice so the onPostExecute method called 2 times, thanks for help.
I figured out after passing my time debugging all the code, when the activity is created it changes the screen orientation and so it creates a second instance, so my AsyncTask is called twice and thats why i thought onPosteExecute is called twice, thanks for everyone who tried to help.

Android - problems with recieving image from SQLite DB [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
So I get a null pointer exception when trying to recieve image from SQLite database.
Saving image:
public void insertImage(byte[] imageBytes) {
ContentValues cv = new ContentValues();
cv.put(IMAGE, imageBytes);
mDb.insert(IMAGES_TABLE, null, cv);
}
Here's my code for recieving the image in the helper class:
public byte[] retreiveImageFromDB() {
Cursor cur = mDb.query(true, IMAGES_TABLE, new String[]{IMAGE,},
null, null, null, null,
IMAGE_ID + " DESC", "1");
if (cur.moveToFirst()) {
byte[] blob = cur.getBlob(cur.getColumnIndex(IMAGE));
cur.close();
return blob;
}
cur.close();
return null;
}
And here's how I try to set the image to ImageView in my activity:
byte[] image = mImage.retreiveImageFromDB();
Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
profileImage.setImageBitmap(bitmap);
What am I doing wrong?
What am I doing wrong?
You are likely not checking for null being returned from the retreiveImageFromDB method.
Instead of :-
byte[] image = mImage.retreiveImageFromDB();
Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
profileImage.setImageBitmap(bitmap);
You should have something along the lines of :-
byte[] image = mImage.retreiveImageFromDB();
if (image != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
profileImage.setImageBitmap(bitmap);
} else {
// Hanlde null here e.g.
Toast.makeText(this,"Ooops image is null!!!",Toast.LENGTH_SHORT).show();
}
You may then ask Why is the Cursor empty!
As the query should return at least 1 row if any exist (i.e the restrictions are only uniqueness of the images (blobs) and the number of rows being returned as 1) then there is a likelihood that you may have issues beyond the scope of what is ascertainable from the code given.
You could perhaps change the insertImage method to return the ID of the inserted row, and check this whenever the method is called e.g.
public long insertImage(byte[] imageBytes) { // <<<< changed signature
ContentValues cv = new ContentValues();
cv.put(IMAGE, imageBytes);
return mDb.insert(IMAGES_TABLE, null, cv); // added return
}
Then use something like :-
if (insertImage(your_image) > 0) {
Log.d("IMAGEINSERT","Image inserted OK.");
} else {
Log.d("IMAGEINSERT","Image was not inserted!!!");
}
Instead of
insertImage(your_image);
You could perhaps utilise the utilities provided at this link, these will allow you to inspect the database and tables.

Changing contact's image to a large photo via PHOTO_FILE_ID in Android

This seems to work for small images:
ContentValues values = new ContentValues();
values.put(ContactsContract.Data.RAW_CONTACT_ID, id);
values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, photo);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
if (photoRow >= 0) {
context.getContentResolver().update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data._ID + " = " + photoRow, null);
} else {
context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}
From the docs I realise that for large images I need to set the PHOTO_FILE_ID, so I can replace:
ContactsContract.CommonDataKinds.Photo.PHOTO
with:
ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID
However, then I need to supply a PHOTO_FILE_ID rather than raw data. My question:
How do I save the photo (byte []) and get a PHOTO_FILE_ID?
If there is already a photo available (PHOTO not PHOTO_FILE_ID). Do I need to delete it for the big image to be seen or does the big image take precedence, if not, how do I delete it?
Your own answer will work, but it's not very efficient because the photo needs to be encoded into an SQL query and piped through Android IPC. That also makes it a subject to Android's IPC size limit of 1MB (i.e. if your photo is too large the content provider operation will fail).
The most efficient way to set (create or override) a RawContact's (primary) photo is by using openAssetFileDescriptor and a ContactsContract.RawContacts.DisplayPhoto URI like so (example copied from Android docs):
public void writeDisplayPhoto(long rawContactId, byte[] photo) {
Uri rawContactPhotoUri = Uri.withAppendedPath(
ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
try {
AssetFileDescriptor fd =
getContentResolver().openAssetFileDescriptor(rawContactPhotoUri, "rw");
OutputStream os = fd.createOutputStream();
os.write(photo);
os.close();
fd.close();
} catch (IOException e) {
// Handle error cases.
}
}
The only drawback of this approach is that it always creates/replaces the primary photo of the RawContact. If the RawContact doesn't have a photo yet this will add one.
Unfortunately there is no way to use openAssetFileDescriptor with a PHOTO_FILE_ID, so you can't override a specific photo identified by its ID using this method. However, in real life most contacts probably have at most one photo, so that's not a real limitation.
This will automatically update the Photo.PHOTO column with a thumbnail of the large photo and assign a PHOTO_FILE_ID.
Finally was able to solve it with:
public void changeContactImage(String contactId, byte[] b) {
ArrayList < ContentProviderOperation > ops = new ArrayList < > ();
ops.add(ContentProviderOperation
.newUpdate(
ContactsContract.Data.CONTENT_URI)
.withSelection(
ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?",
new String[] {
contactId,
ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
})
.withValue(ContactsContract.CommonDataKinds.Photo.DATA15, b).build());
// Do something with the phone number...
try {
context.getContentResolver().
applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
Log.d("RemoteException", e.toString());
} catch (OperationApplicationException e) {
Log.d("OperationException", e.toString());
}
}
The PHOTO_FILE_ID is the ID not of a file (confusingly) but of a row in the database which contains your raw photo data. According to the docs I've looked at you can actually avoid using it (from the docs) :
Under PHOTO_FILE_ID
If present, this will be used to populate PHOTO_URI
and Under PHOTO_ID (which is guaranteed populated if PHOTO_FILE_ID exists)
Reference to the row in the data table holding the photo. A photo can be referred to either by ID (this field) or by URI (see PHOTO_THUMBNAIL_URI and PHOTO_URI)
This implies that if you just use PHOTO_URI you will get the same resulting image as if you made the method openDisplayPhoto. It also suggests that the URI methods are better compatible with 3rd part directories so are probably preferable to work with
You can get the contact photo uri without using ContactsContract.CommonDataKinds.Email.PHOTO_URI this way:
Read Full Answer here More
Where! to get Contact URI as you said try this:
import android.provider.ContactsContract.PhoneLookup;
public String fetchContactIdFromPhoneNumber(String phoneNumber) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber));
Cursor cursor = this.getContentResolver().query(uri,
new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
null, null, null);
String contactId = "";
if (cursor.moveToFirst()) {
do {
contactId = cursor.getString(cursor
.getColumnIndex(PhoneLookup._ID));
} while (cursor.moveToNext());
}
return contactId;
}
To get the conatct id using the phone number use the following code:
import android.provider.ContactsContract.PhoneLookup;
public String fetchContactIdFromPhoneNumber(String phoneNumber) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber));
Cursor cursor = this.getContentResolver().query(uri,
new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
null, null, null);
String contactId = "";
if (cursor.moveToFirst()) {
do {
contactId = cursor.getString(cursor
.getColumnIndex(PhoneLookup._ID));
} while (cursor.moveToNext());
}
return contactId;
}
and use the contact id obtained to get the contatc photo URI. Use the following code for getting photo URI:
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
public Uri getPhotoUri(long contactId) {
ContentResolver contentResolver = getContentResolver();
try {
Cursor cursor = contentResolver
.query(ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID
+ "="
+ contactId
+ " AND "
+ ContactsContract.Data.MIMETYPE
+ "='"
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
+ "'", null, null);
if (cursor != null) {
if (!cursor.moveToFirst()) {
return null; // no photo
}
} else {
return null; // error in cursor process
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
Uri person = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, contactId);
return Uri.withAppendedPath(person,
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
}
Please let me know if this does not answer your question

Most robust way to fetch album art in Android

Please note that I have already been through similar questions and their answers here and on other websites. I also have a solution that works on some devices (my G2X running CyanogenMod 7.1, my wife's HD2 running a custom ROM and the emulator running Android 2.1). It doesn't, however work on my Nook running CyanogenMod.
My question is: What is the most robust and general way to fetch album art on all android devices? What are the gotchas for specific devices, versions or music applications (I don't mean third-party players, I mean Google Music versus the old Music client)? My current code is:
// Is this what's making my code fail on other devices?
public final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
// This works, and well on all devices
private int[] getAlbumIds(ContentResolver contentResolver)
{
List<Integer> result = new ArrayList<Integer>();
Cursor cursor = contentResolver.query(MediaStore.Audio.Media.getContentUri("external"), new String[]{MediaStore.Audio.Media.ALBUM_ID}, null, null, null);
if (cursor.moveToFirst())
{
do{
int albumId = cursor.getInt(0);
if (!result.contains(albumId))
result.add(albumId);
} while (cursor.moveToNext());
}
int[] resultArray = new int[result.size()];
for (int i = 0; i < result.size(); i++)
resultArray[i] = result.get(i);
return resultArray;
}
// This is the bit I want to make more robust, make sure that it works on all devices
private Shader getAlbumArt(ContentResolver contentResolver, int albumId, int width, int height)
{
Uri uri = ContentUris.withAppendedId(sArtworkUri, albumId);
InputStream input = null;
try {
input = contentResolver.openInputStream(uri);
if (input == null)
return null;
Bitmap artwork = BitmapFactory.decodeStream(input);
input.close();
if (artwork == null)
return null;
Bitmap scaled = Bitmap.createScaledBitmap(artwork, width, height, true);
if (scaled == null)
return null;
if (scaled != artwork)
artwork.recycle();
artwork = scaled;
return new BitmapShader(artwork, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Thanks in advance,
Ananth
Here i can attach one function that is return album art from media store . Here in function we just have to pass the album_id which we get from Media store .
public Bitmap getAlbumart(Long album_id)
{
Bitmap bm = null;
try
{
final Uri sArtworkUri = Uri
.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
ParcelFileDescriptor pfd = context.getContentResolver()
.openFileDescriptor(uri, "r");
if (pfd != null)
{
FileDescriptor fd = pfd.getFileDescriptor();
bm = BitmapFactory.decodeFileDescriptor(fd);
}
} catch (Exception e) {
}
return bm;
}
Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
ContentResolver res = context.getContentResolver();
InputStream in = res.openInputStream(uri);
Bitmap artwork = BitmapFactory.decodeStream(in);
More complete sample code can be found in Android Music player source here https://github.com/android/platform_packages_apps_music/blob/master/src/com/android/music/MusicUtils.java method getArtworkQuick.
This below code snippet returns the uri for the album art cache present in the MediaStore. may be this will help.
Cursor cursorAudio = managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, {MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.DATA}, MediaStore.Audio.Media.DATA+ " LIKE \"" + path+ "\"", null, null);if(cursorAudio != null && cursorAudio.moveToFirst()){
Long albumId = Long.valueOf(cursorAudio.getString(cursorAudio.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)));
cursorAudio.close();
Cursor cursorAlbum = managedQuery(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, {MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART}, MediaStore.Audio.Albums._ID+ "=" + albumId, null, null);
if(cursorAlbum != null && cursorAlbum.moveToFirst()){
String uri = cursorAlbum.getString(cursorAlbum.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
cursorAlbum.close();
if(uri != null){
return Uri.parse(uri);
}
}
I'd like to modify Chirag Raval's answer by using Picasso library. It is simple to use and very powerful.
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri, arrayList.get(i).getArt());
Picasso.with(context).load(uri).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher)
.into(ivPic);
For full documentation, refer this.

Categories

Resources