I'm having problems getting and setting a contact's image as a view's background, surprisingly there are few examples on how to do it. I'm trying to build something similar to the People app which displays big contact photos.
This is what I'm doing right now:
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.valueOf(id));
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
Bitmap bm = BitmapFactory.decodeStream(input);
Drawable d = new BitmapDrawable(bm);
button.setBackgroundDrawable(drawable);
This works however the URI it uses gets a thumbnail picture, so even if there is a big photo images looks very bad when scaled to fit the imageView. I know another method to get the URI that actually gets a big photo which is:
final Uri imageUri = Uri.parse(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.PHOTO_URI)));
However I haven't managed to get it to the imageView, maybe the code above can be adapted to use the second uri. If you know how to use the second uri or if there is an easier way to get the contact image than through the URI please tell me. Any info will be thanked.
Good job in getting the URI. You're almost there. First of all consider using PHOTO_THUMBNAIL_URI instead of PHOTO_URI, as it may be what you need in terms of size.
Edit : FYI, PHOTO_THUMBNAIL_URI is available starting API 11. You can still use it conditionally.
If you want to use an external library, 'Android Universal Image Loader' is definitely what you are looking for, as starting from it's 1.7.1 version from a few days ago, it added support for content schemes and it is pretty smart, memory wise. It also has a lot of customization options.
Edit: this lib is already dead. Use Fresco instead.
If you'd rather be nicer to your final bundle size and write the code yourself,
You need to get and decode the input stream of that content; This should be done on a background thread. Check out this connivence method; You initialise it with your image view and the uri you got and start it when you want to load the ImageView.
private class ContactThumbnailTask extends AsyncTask<Void, Void, Bitmap> {
private WeakReference<ImageView> imageViewWeakReference;
private Uri uri;
private String path;
private Context context;
public ContactThumbnailTask(ImageView imageView, Uri uri, Context context) {
this.uri = uri;
this.imageViewWeakReference = new WeakReference<ImageView>(imageView);
this.path = (String)imageViewWeakReference.get().getTag(); // to make sure we don't put the wrong image on callback
this.context = context;
}
#Override
protected Bitmap doInBackground(Void... params) {
InputStream is = null;
try {
is = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap image = null;
if (null!= is)
image= BitmapFactory.decodeStream(is);
return image;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewWeakReference != null && imageViewWeakReference.get() != null && ((String)imageViewWeakReference.get().getTag()).equals(path) && null != bitmap)
imageViewWeakReference.get().setImageBitmap(bitmap);
}
}
It is suggestion. First know one thing.
When you set a contacts image. First Android show the Cropping activity for that image. Like
****carefully see above image. Android crop the image as square shape. And store the square shape image as a Blob in contacts.(It is not individual image. It is blob.)
You get a square shape image for your image view from your coding. so top and bottom show black color only. Because your mobile in rectangle shape.****
If you want to show full screen image. Please set a big image to contacts through programmatically. Lot of examples available in internet.
All the best for your try. If you have any doubts. Please provide comments.
You can try using SmartImageView: http://loopj.com/android-smart-image-view/ extends imageview and also loads images asynchronously.
Use an external library to do that for you. Or browse the code and make something similar your own way.
Here's one I use on several of my own apps: UrlImageViewHelper
The code would go like this:
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.valueOf(id));
UrlImageViewHelper.setUrlDrawable(button, uri.toString(), R.drawable.dummy_contact_photo);
You can easily set the contact photo to the image view by using the following method.
public String getImageUriString(String phoneNumber)
{
ContentResolver resolver = context.getContentResolver();
Cursor names = resolver.query(
Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber)),
null, null, null, null);
names.moveToFirst();
String name = "";
if(!names.isAfterLast())
{
name = names.getString(names.getColumnIndex(ContactsContract.PhoneLookup.PHOTO_URI));
}
else
{
name = null;
}
names.close();
return name;
}
public void setImageView(ImageView contactPhoto) {
String photoUriString = di.getImageUriString(contactNumber);
if(photoUriString != null) {
Uri photoUri = Uri.parse(photoUriString);
contactPhoto.setImageURI(photoUri);
} else {
contactPhoto.setImageResource(R.drawable.icon_contact);
}
}
From your class, set the image view with the uri getting from the above method.
To be able to do that you have to just add one last parameter preferHighres = true:
openContactPhotoInputStream (ContentResolver cr, Uri contactUri, boolean preferHighres)
If preferHighres is true and the contact has a higher resolution photo available, it is returned. If false, this function always tries to get the thumbnail
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.valueOf(id));
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri, true);
All the images probably would have differnet sizes. In order to resize them I use next code:
Bitmap bm = BitmapFactory.decodeStream(input);
bm = Bitmap.createScaledBitmap(photo, contactImageWidth, contactImageheight, false);
Drawable d = new BitmapDrawable(getContext(), bm);
button.setBackgroundDrawable(d);
Related
I want to allow users to upload images into my app from their gallery and then I will save their uri in my DB to keep track of upload. Right now I'm getting the Uri from uploaded images as referenced in this SO Answer:
Get file path of image on Android
The issue with this answer is it requires the image to be saved a second time.
String path = MediaStore.Images.Media.insertImage(context, img, "title, null);
I don't want to create duplicate images in a users gallery but I need to get the Uri from the image they upload. Any suggestions?
Code I'm using now to get the image Uri:
Uri selectedImage = data.getData();
Log.d(TAG, "Imediate Uri: " + selectedImage);
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
Uri tempUri = getImageUri(getApplicationContext(), bitmap);
public Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
I'd suggest posting the image to a storage bucket, like Amazon S3, Firebase Storage / Google Cloud Storage. This'll generate a URI / URL, and you could post that URI to your database.
I'm not sure if this entirely answers your question but I hope I might have pointed you somewhere in a good direction.
P.S.: Most of those storage solutions also have built-in APIs so you wouldn't be obligated to post the URI to the databse.
I'm now developing an app using android studio. Now I want to use an image file which is stored at my desktop. Then I also need its uri to do something. Now I put it in drawable file, but I don't know how to call it as a file and get its url.
I think I should implement something like this:
File file = new File(?????);
Uri uri = Uri.fromfile(file);
What should I put inside the clause? I've tried "res:///"+R.drawable.image, but it doesn't work. Can someone help me?
If you want to use your image as Bitmap (as far as i understand from your question)
Use this for getting bitmap from drawable folder.
Bitmap image= BitmapFactory.decodeResource(context.getResources(), R.drawable.image_name);
Then you can save this bitmap to the telephone for uri but i think you are trying to access bitmap of it.
To create a file from uri, you also need to provide the file path
Add the following method to your activity outside the onCreate method
private String getPath(Uri contentUri) {
String[] proj = {MediaStore.Images.Media.DATA};
CursorLoader loader = new CursorLoader(getContext(), contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
and then create file like this
String filePath = getPath(put your uri here);
File file = new File(filePath);
Hope it works for you
you can get Uri, you will replace pic1 with your image name
Uri uri = Uri.parse("android.resource://"+this.getPackageName()+"/drawable/pic1");
img.setImageURI(uri);
try to use ContentResolver to open resource URIs:
Uri uri = Uri.parse("android.resource://your.package.name/drawable/image_filename");
//To open file
InputStream stream = getContentResolver().openInputStream(uri);
Just getting into the Glide image loading library for Android. Currently working with some code from here:
https://github.com/bumptech/glide/issues/459
My full project is here is you want to look at it:
https://github.com/mhurwicz/glide02
I'm getting the following exception when I run the app in the emulator in Android Studio:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
This is the key statement in MainActivity:
new ShareTask(this).execute("http://thelink");
(thelink is actually goo.gl/gEgYUd -- couldn't leave that in above because stackoverflow doesn't allow URL shorteners. )
Here is my code for the ShareTask class
class ShareTask extends AsyncTask<String, Void, File> {
private final Context context;
public ShareTask(Context context) {
this.context = context;
}
#Override protected File doInBackground(String... params) {
String url = params[0]; // should be easy to extend to share multiple images at once
try {
return Glide
.with(context)
.load(url)
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get() // needs to be called on background thread
;
} catch (Exception ex) {
Log.w("SHARE", "Sharing " + url + " failed", ex);
return null;
}
}
#Override protected void onPostExecute(File result) {
if (result == null) { return; }
Uri uri = FileProvider.getUriForFile(context, context.getPackageName(), result);
share(uri); // startActivity probably needs UI thread
}
private void share(Uri result) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_SUBJECT, "Shared image");
intent.putExtra(Intent.EXTRA_TEXT, "Look what I found!");
intent.putExtra(Intent.EXTRA_STREAM, result);
context.startActivity(Intent.createChooser(intent, "Share image"));
}
}
Using debug, it seems I may be running into trouble at the get() statement. For one thing, the width and the height are very large negative numbers. (See the code highlighted in green below.) Then the get() statement returns null. (See the code highlighted in red below.)
Thanks in advance for any help you can provide!
The NPE is coming from FileProvider.getUriForFile because you're passing in the wrong authority. You declared android:authorities="com.example.fileprovider" in the manifest, but you're using the package name at the call. This fails to resolve the info in FileProvider.parsePathStrategy. Match those two strings up and you'll be good to go.
The easiest fix is to use android:authorities="${applicationId}", this leads to 0 hardcoded strings, so you can keep using context.getPackageName().
Regarding your concerns during debug:
Target.SIZE_ORIGINAL is declared to be MIN_VALUE, hence the large number
it's not returning null, IDEA is just confused about where it is in the method, that return null; shouldn't be executed if it fails in the FileProvider code.
doGet(null): null is the timeout here, it's guarded properly in code
I've run the app and weirdly I got a log line saying
W/SHARE: Sharing http://... failed
but not a stack trace, which is weird, because ex cannot be null in a catch!
I'm grabbing thumbnail images from a web server in an AsynTask for each class I create as it's created. For this particular issue, I'm displaying the thumbnail and some text properties in a ListView.
The problem is that it's very slow. I considered saving each image to the device the first time it's needed and then each other time, I could just pull it from a database. I'm not sure if this is ideal or not because the image may or may not be updated on the server. In my opinion, I think it's best to always grab the images on the fly just in case there are new ones to grab.
I'd like some suggestions from all you fine folks about this.
Note: I've also tried getting the images in a ListView adapter but 1) it gets each image each and every time the ListView is scrolled and 2) it's incredibly buggy because as each image downloads, I can watch the images appear in the wrong listview item and then it magically corrects itself after a while. This wasn't at all ideal so that's why I moved the code to the class.
I'd appreciate any advice that's thrown my way.
Here's the getter for the image that lives in the class. This works fine after the image is downloaded the first time but not so well during that initial run.
public Bitmap GetThumbnail_xlarge() throws Exception {
if(_thumbnail_xlarge == null ) {
if( _thumbnailBasePath != null) {
try {new DownloadImageTask(_thumbnail_xlarge).execute(_thumbnailBasePath + "/portrait_xlarge." + _thumbnailExtension); }
catch (Exception e) {} //TODO: The extension could be incorrect. Do nothing for now.
}
else{ throw new Exception("You must set the thumbnail path before getting the image"); }
}
return _thumbnail_xlarge;
}
And, here is the class that does the work. Please note that this is a private class inside of the class where the image property lives:
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
Bitmap bmImage;
public DownloadImageTask(Bitmap bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) { _thumbnail_xlarge = result; }
}
I can't think of anything else that might be pertinent at this time. Please ask me for more information if necessary and thanks in advance!
It's incredibly useful to save images locally for later use. This called caching by the way. It's useful, as you are saving resources and you can reduce network requests which are using plenty of them.
If the images are big you can use the WebP format. WebP is an image format which is "lossless and lossy compression for images on the web. WebP lossless images are 26% smaller in size compared to PNGs. WebP lossy images are 25-34% smaller in size compared to JPEG images at equivalent SSIM index."
More info regarding WebP format you can find here: https://developers.google.com/speed/webp/?csw=1
Also if you want to load images smoothly on a ListView you have to use the ViewHolder pattern. More info here: http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder
So in my app it is receiving an image from another application
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
handleSendImage(intent); // Handle single image being sent
public void handleSendImage(Intent a)
{
Uri pic = (Uri) a.getParcelableExtra(Intent.EXTRA_STREAM);
}
From here I want to save the Uri as an image in my image gallery.
I know how to save a file in the gallery I am just not sure how I get the Uri in the correct format to save it. I know it contains the image because picView.setImageURI(pic); causes the picture to appear in my activity. I just want to be able to save that image into the gallery. Any ideas on how I would do that? I thought that I could convert the ImageView to a bitmap and go from there but that seems really inefficient to me and there has to be a better way to do it. Since I know you can create Uris from Files but can you create a File from a Uri?