Android ImageView unable to access some contact photos - android

I get the contact ID (ContactsContract.Contacts._ID)
I determine if a photo is available by checking if the corrisponding ContactsContract.Contacts.PHOTO_ID is null.
If it's not I build a URI to the photo:
Uri personUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,id);
Uri photoUri=Uri.withAppendedPath(personUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
Then I set the photoUri to an ImageView using its setImageURI method.
For some photos I see the picture for other contacts I get the following exception:
Unable to open content: content://com.android.contacts/contacts/1912/photo
java.io.FileNotFoundException: java.io.FileNotFoundException: No results.
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:123)
at android.content.ContentProviderProxy.openAssetFile(ContentProviderNative.java:538)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:484)
at android.content.ContentResolver.openInputStream(ContentResolver.java:319)
at android.widget.ImageView.resolveUri(ImageView.java:521)
at android.widget.ImageView.setImageURI(ImageView.java:305)
I'm not sure why it is not working for some contacts?
But mostly I'd like do know what should I test for in order to avoid this exception?

You can use ContactsContract.Contacts.openContactPhotoInputStream(Context, Uri) method to check if the photo associated with a contact is readable or not.
E.g.
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(getContext().getContentResolver(), personUri);
if (is == null) {
// Your contact doesn't have a valid photo
// i.e. use the default photo for your app
} else {
// This will always succeed when assigned to an ImageView!
return Uri photoUri=Uri.withAppendedPath(personUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
}

Related

Get file name from Uri in Android

I have an Uri build using below code
final Uri fileUri = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, docId);
that contains value:
content://com.android.externalstorage.documents/tree/primary%Sample/document/primary%Sample%2FMedia%2F.Hide%2FScreenshot_1615959401.png/children
Below is my code to access the name and mime type of file:
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(fileUri, new String[]{DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE}, null, null, null);
try {
if (cursor != null && cursor.moveToFirst())
{
//Here cursor.moveToFirst() returns false
}
} catch(Exception e)
{
e.printStackTrace();
}
I want to access the name of file like Screenshot_1615959401.png, mime type file like image/png from above Uri but cursor.moveToFirst() returns 0. Why record is not found even Uri is valid. Because I try to use this Uri to load image and ImageView is displaying the image correctly using above Uri.
Any Help would be highly appreciated as I spent lots of time googling and read on SO but didn't find any solution or root cause of it.
Below is my code to access the name and mime type of file:
That Uri is not for a document. It is for the roster of child documents for a document tree, where the tree is identified by docId. childDocumentsUri is the core of the name of the method that you are calling.
Why record is not found even Uri is valid
It is not valid for your desired action.
If you wish to build a Uri for a document, given a document ID and a tree, use buildDocumentUriUsingTree(), not buildChildDocumentsUriUsingTree().

Get a Content URI from a File URI?

I am using the DownloadManager to download an image to the system's gallery and then in the Broadcast receiver (once the download succeeds) using an Intent to set the image as the wallpaper.
Everything was working fine but then recently on 4.4 I started to get an exception in the Photos/Google+ app because it is expecting a content URI and not a file URI.
So my question is if anyone knows how to convert a full file path/URI (file://) into a content style URI (content://)?
Sorry for the lack of source code, I am away from the computer that has the source, but I hope the question makes sense without it, get a content style uri from a full path.
EDIT:
The image is copied into the system's gallery or media gallery, not saved within my apps internal storeage.
Here is an example of what I want to convert:
file:///storage/emulated/0/Pictures/Rockstar/image.jpg
to
content://media/internal/images/media/445
EDIT 2:
Here is the error that I get from the Google+ app:
04-21 10:50:35.090: E/AndroidRuntime(7220): FATAL EXCEPTION: main
04-21 10:50:35.090: E/AndroidRuntime(7220): Process: com.google.android.apps.plus, PID: 7220
04-21 10:50:35.090: E/AndroidRuntime(7220): java.lang.RuntimeException: Unable to resume activity
{com.google.android.apps.plus/com.google.android.apps.photos.phone.SetWallpaperActivity}:
java.lang.IllegalArgumentException: Image URI must be of the content scheme type
Here is the code that I use to let the user set the wallpaper:
String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
Uri u = Uri.parse(uriString);
Intent wall_intent = new Intent(Intent.ACTION_ATTACH_DATA);
wall_intent.setDataAndType(u, "image/*");
wall_intent.putExtra("mimeType", "image/*");
Intent chooserIntent = Intent.createChooser(wall_intent,
"Set As");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(chooserIntent);
}
Where uriString is:
file:///storage/emulated/0/Pictures/Rockstar/image.jpg
I was able to figure it out. It was a combination of the code found here: Converting android image URI and scanning the media file after downloading.
So after the file finished downloading I get the path and do the following:
String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
//Update the System
Uri u = Uri.parse(uriString);
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, u));
//Get the abs path using a file, this is important
File wallpaper_file = new File(u.getPath());
Uri contentURI = getImageContentUri(context, wallpaper_file.getAbsolutePath());
For some reason starting the media scanner, newing the file, and getting the absolute path are important, I'm not exactly sure why but I can't spend any more time on this!
The way to convert from a file URI to a content URI is as follows (taken from the linked StackOver flow post:
public static Uri getImageContentUri(Context context, String absPath) {
Log.v(TAG, "getImageContentUri: " + absPath);
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
, new String[] { MediaStore.Images.Media._ID }
, MediaStore.Images.Media.DATA + "=? "
, new String[] { absPath }, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI , Integer.toString(id));
} else if (!absPath.isEmpty()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, absPath);
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
Maybe this will help someone in the future.
So my question is if anyone knows how to convert a full file path/URI (file://) into a content style URI (content://)?
Implement a ContentProvider. FileProvider offers an out-of-the-box solution for serving up local files.
I'm not sure about the technique you are using to set the wallpaper but the easiest way is probably to use WallpaperManager.setStream() which doesn't require any URI.
Also note that a file URI only works between apps if the file is publicly accessible so a content URI is a more general solution.
Using a content URI implies that a ContentProvider will serve the file. Which one depends on where your file is located.
If your app has a direct read access to the file, you can implement a content provider in your app by using for example the FileProvider class of the support library, but this should really only be used if the file is located in the private data storage of your app.
If the image is added to the system media gallery, you should probably use the URI provided by the MediaStore.

Android: resolving uri from content provider, fetching player avatar (Android Game services)

I'm stucked during the Game Services implementation in some of our games. I can't retrieve the user image (using Unity). I can get the Uri of the image (Uri from a content provider), but I cant use ImageManager because it stores the data in a imageView, and I want the url/path of the image to let Unity handle all the data.
My best try is setting a ContentResolver but I get a security error:
Permission Denial: opening provider com.google.android.gms.games.provider.GamesContentProvider
At this point I can't find any solution on that, in fact I'm not able to find anything related with GamesContentProvider at all. So I don't know where to find the right way to retrieve the data or find the permission.
Here you have part of the code:
public String getAvatarUrlGame(boolean highRes)
{
String n = "";
if (isSignedIn()) {
Uri uri;
if(highRes) uri = getGamesClient().getCurrentPlayer().getHiResImageUri();
else uri = getGamesClient().getCurrentPlayer().getIconImageUri();
if (uri != null)
{
Cursor cursor = this.getContentResolver().query(uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
cursor.moveToFirst();
n = cursor.getString(0);
cursor.close();
}
}
return n;
}
Any help will be apreciated. Thanks in advance!
The only way to access the images is via ImageManager. You can't use a content resolver. If you only want the images and don't want to handle ImageView's, you can use ImageManager.loadImage(OnImageLoadedListener, Uri), which will call your OnImageLoadedListener with a Drawable representing the image.
Then, to get a Unity-compatible bitmap from the Drawable, just convert it to a bitmap. For info on how to do this step, see this answer, particularly André's answer (the one that has the drawableToBitmap method).
Hope this helps!

Fetching attachments with custom extension in my Android application

What I am trying to achieve is sounds very familiar, it has been posted many times here and there in Stack Overflow as well, but I'm unable to get it done.
The scenario is, I receive a mail with attachment having custom extension in it. The extension is recognized by my app and it needs the FilePath to process it.
Currently, when I get the attachment in my app using getIntent().getData() all I get is path of the form content://
I have seen methods to convert media content of the type content:// to FilePath like /sdcard/file.ext but I was unable to convert the attachment using that. May be its obvious.
Is there any way that I can process the content:// type without actually downloading it.
Currently from the k9 mail app, when I get the custom extension, it shows my app in the list and opens it through it, but I need FilePath like /sdcard/file.ext and I'm only able to get content:// type.
I hope I made the question clear.
Please Help.
Regards.
A content:// Uri does not necessarily point to a file on the sdcard.
It is more likely that it points to any kind of data stored in a database
or to a content provider that gives you access to the private file storage of another app.
I think the later one is the case with mail attachments (if the content provider is not requesting it directly from a web server). So converting the content:// Uri to a path will not work.
I did the following (not sure if it works also for k9 mail app)
Uri uri = intent.getData();
if (uri.getScheme().equals("content")) {
String fileName = ContentProviderUtils.getAttachmentName(this, uri);
if (fileName.toLowerCase().endsWith(".ext")) {
InputStream is = this.getContentResolver().openInputStream(uri);
// do something
} else {
// not correct extension
return;
}
} else if (uri.getScheme().equals("file")) {
String path = uri.getPath();
if (path.toLowerCase().endsWith(".ext")) {
InputStream is = new FileInputStream(path);
// do something
} else {
// not correct extension
return;
}
}
The attachment name can be found by
public static String getAttachmentName(Context ctxt, Uri contentUri) {
Cursor cursor = ctxt.getContentResolver().query(contentUri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
String res = "";
if (cursor != null){
cursor.moveToFirst();
int nameIdx = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
res = cursor.getString(nameIdx);
cursor.close();
}
return res;
}

How to pass a single Image with Intent which uses content uri (_not_ file uri) in Android

(I have read a lot of similar questions, but bear with me here)
I need to send an image from one Activity (custom camera acitvity), where the second Activity is to upload the image to Picasa Web Album via Google API.
Every example I've found goes something like this:
File f = new File(cacheDir, "image_name.jpg");
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
startActivity(intent);
This works perfectly fine when I use the standard Android Picasa upload activity (or any other sharing app). I can also upload photos via the Picasa example app I am using, when sharing the image from gallery/camera etc.
But I cannot figure out how to build an Intent which uses a "content://---" uri and pass this to another application (neither for this example app or the Picasa standard app)...
Specificially: How can I create an Intent which is compatible with the code below (i.e. uses "content://" uri instead of "file://" uri)?
static class SendData {
String fileName;
Uri uri;
String contentType;
long contentLength;
SendData(Intent intent, ContentResolver contentResolver) {
Bundle extras = intent.getExtras();
if (extras.containsKey(Intent.EXTRA_STREAM)) {
Uri uri = this.uri = (Uri) extras.get(Intent.EXTRA_STREAM);
String scheme = uri.getScheme();
if (scheme.equals("content")) {
Cursor cursor = contentResolver.query(uri, null, null, null, null);
cursor.moveToFirst();
this.fileName = cursor.getString(cursor.getColumnIndexOrThrow(Images.Media.DISPLAY_NAME));
this.contentType = intent.getType();
this.contentLength = cursor.getLong(cursor.getColumnIndexOrThrow(Images.Media.SIZE));
}
}
}
}
Retrieving the File-information from a File uri manually leads to NullPointerException with the Google Http Request used in the app.
Hardcoding the Content uri works. E.g:
uploadIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://media/external/images/media/11"));
Information related to Media files is stored by the MediaStore, which is a ContentProvider (http://developer.android.com/reference/android/provider/MediaStore.Images.html)
MediaStore.Images.DATA column corresponds to the file path and MediaStore.Images._ID column corresponds to the ID.
You need to query for the ID corresponding to your file path and then create a ContentUri out of it (which will be MediaStore.Images.Media.EXTERNAL_CONTENT_URI + id if the image is on the external storage, I'll try to think of a better way to translate the ID into a Content Uri).
http://developer.android.com/reference/android/provider/MediaStore.Images.Media.html#query(android.content.ContentResolver, android.net.Uri, java.lang.String[]

Categories

Resources