I am querying the Images table to get all pictures in the MediaStore.Images.Media.EXTERNAL_CONTENT_URI directory.
See the following query:
String[] what = new String[]{ MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.MIME_TYPE,
MediaStore.Images.ImageColumns.DATA };
String where = MediaStore.Images.Media.MIME_TYPE + "='image/jpeg'" +
" OR " + MediaStore.Images.Media.MIME_TYPE + "='image/png’";
Cursor cursor = getContext().getContentResolver()
.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
what,
where,
null,
MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC”);
Now, I’d like to have an Uri pointing to each of the result.
This is what I am doing right now:
int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
String path = cursor.getString(dataIndex);
final Uri uri = Uri.fromFile(new File(path));
E.g., I take the path from the DATA column, create a file and use Uri.fromFile. I have two questions.
Is this guaranteed to work? Is the query above guaranteed to return paths in the data column? It works for all the pictures in my phone: path is always a path, like /storage/0/whatever.jpg, and uri.toString() is the same but with the file scheme. Still, pictures can very well be defined by content:// uris, but I fail to see how (and if) these are represented in the images table.
If not, what should I expect in the DATA column, and how to get an Uri from it?
Is the query above guaranteed to return paths in the data column?
It should return something. That "something" may not be usable. For example, the image might be on removable storage, and you cannot access it directly.
how to get an Uri from it?
You don't. You construct a Uri from the _ID:
Uri imageUri=
ContentUris
.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)));
Related
I have been retrieving images from MediaStore in the following way...
Uri uriExternal = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = {
MediaStore.MediaColumns._ID,
MediaStore.MediaColumns.DATE_ADDED
};
Cursor cursor = getContentResolver()
.query(uriExternal, projection,
MediaStore.MediaColumns.DATA + " IS NOT NULL",
null,
MediaStore.MediaColumns.DATE_ADDED + " DESC");
if(cursor != null) {
while (cursor.moveToNext()) {
String _id = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
paths.add(uriExternal.toString() + "/" + _id);
}
cursor.close();
}
Basically, I'm simply appending the file id to the external content provider uri. This makes a uri that I can use with content providers...
content://media/external/images/media/{id}
It all works perfectly fine, all external images are displayed and loaded flawlessly. However, since I've failed to find proper documentation, I'm a little concerned I'm not doing things the proper way. Especially because of the way I'm constructing the uri...kind of hard-coding it...
The questions are...
Is this the correct way to construct a content uri for an external image?
Is there a more reliable way to achieve this?
Personally, I use ContentUris.withAppendedId(). That way, I don't have to worry about whether I am starting with a Uri that ends in / or not. :-)
In general, MediaStore adheres to the original ContentProvider vision of using the content ID as the last path segment of a Uri pointing to the content. However, that is not a general rule, and it will not work for all providers.
I had this working at a time, but now it fails every time I try to get the file path. I am receiving the file from Acrobat Reader and can receive the file name and size, but not the relative file path.
My code looks like this:
if(uri.getScheme().equals("content"))
{
String[] dataFields = new String[]{
MediaStore.MediaColumns.DATA,
OpenableColumns.DISPLAY_NAME,
OpenableColumns.SIZE};
Cursor cursor = context.getContentResolver().query(uri, dataFields, null, null, null);
cursor.moveToFirst();
fileLocation = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
title = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
size = cursor.getInt(cursor.getColumnIndex(OpenableColumns.SIZE));
cursor.close();
contentType = context.getContentResolver().getType(uri);
}
I get the following error in LogCat:
Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 2 columns.
I understand it as it can't find the column. However, I don't understand how this can be?
A Uri is not a file. There is no requirement that the Uri be from MediaStore or otherwise have a MediaStore.MediaColumns.DATA column. If you want to access the content represented by the Uri, use openInputStream() on a ContentResolver.
I am trying to rename an image in Gallery taken from Camera to give a new name. When I renamed the file the original image disappears showing 2 black squares . Can any one help me in sorting this issue by telling me procedure to rename Gallery Image.
Path is as follows : /mnt/sdcard/DCIM/Camera
I tried to update the Image title through content provider as below:
ContentValues val = new ContentValues();
val.put(Images.Media.TITLE, "ImageTitle23");
getContentResolver().update(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, val, null, null);
The image title is changed in Gallery.
But when I try to query the updated image as below I am getting the name same as previous one :
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, MediaStore.Images.Media._ID+"="+id, null, imageOrderBy);
if(imageCursor.moveToFirst()){
int idd = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
Can anyone help me in sorting out this issue?
The MediaStore looks for changes in your pictures BUT it will not react to all changes in real time. Each time you do such a modification, you should ask the MediaScanner to scan this file:
MediaScannerConnection.scanFile(
getApplicationContext(),
new String[]{file.getAbsolutePath()},
null,
new OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
Log.v("grokkingandroid",
"file " + path + " was scanned seccessfully: " + uri);
}
});
Also, you should check this blog post that gives a lot of useful informations on this usecase.
The Gallery is interacting with the MediaStore content provider. If you change the name of the image file you probably need to update the field in the content provider.
You can read up on it in the MediaStore reference : http://developer.android.com/reference/android/provider/MediaStore.Images.Media.html
Potentially you can just trigger a refresh of the MediaStore. Look at this thread : How can I refresh MediaStore on Android?
In the class MediaStore.Files class, its mentioned that,
Media provider table containing an index of all files in the media storage, including non-media files.
I'm interested in querying for non-media files like PDF.
I'm using CursorLoader to query the database. The second parameter for the constructor requires an Uri argument which is easy to get for the media types Audio, Images and Video as each of them have a EXTERNAL_CONTENT_URI and INTERNAL_CONTENT_URI constant defined for them.
For MediaStore.Files there is no such defined constant. I tried using the getContentUri() method but couldn't figure out the argument value for volumeName. I tried giving "/mnt/sdcard" and also the volume name that appears when I connect the device to my system but in vain.
I saw a similar question on Google Groups but that is not resolved.
EDIT: I also tried using Uri.fromFile(new File("/mnt/sdcard/")) and Uri.parse(new File("/mnt/sdcard").toString()) but that didn't work out either.
It is "external" or "internal" although internal (system files) is probably not useful here.
ContentResolver cr = context.getContentResolver();
Uri uri = MediaStore.Files.getContentUri("external");
// every column, although that is huge waste, you probably need
// BaseColumns.DATA (the path) only.
String[] projection = null;
// exclude media files, they would be here also.
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_NONE;
String[] selectionArgs = null; // there is no ? in selection so null here
String sortOrder = null; // unordered
Cursor allNonMediaFiles = cr.query(uri, projection, selection, selectionArgs, sortOrder);
If you want .pdf only you could check the mimetype
// only pdf
String selectionMimeType = MediaStore.Files.FileColumns.MIME_TYPE + "=?";
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
String[] selectionArgsPdf = new String[]{ mimeType };
Cursor allPdfFiles = cr.query(uri, projection, selectionMimeType, selectionArgsPdf, sortOrder);
I am making a autocomplete Field that queries contacts by Display name and Email. When someone clicks on the desired contact after the filtering that contact is added to a list with his email, display name and Picture if he has any.
So so far i have managed to do everything except to make the Photo appear. Here is how i run the query to get the email, display name, ID , and Photo ID.
return mContent.query(Email.CONTENT_URI,
PROJECTION, filter, null, null);
where projection is:
PROJECTION = new String[] {ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_ID,
Email.DATA
};
This one does what i need and returns all the data. But one thing i noticed during debugging this issue is that the contact id is different than if you run the query against ContactsContract.Contacts.CONTENT_URI for a specific display name for example.
For example the tests i have run where i get all the contacts by running the Contacts.CONTENT_URI gave me a contact with an image and Id of 152. However the query against the Email.CONTENT_URI gives me an id of 452 for the same contact (With same display name and email address). so when i try to get the Photo for a content uri containing the Id 452 it returns that the photo doesnt exist, but if i try to get the photo for 152 it works perfectly.
What is causing this issue? how do i get the correct User ID? Is there any relational query that i can maybe run to get a contact ID, or maybe a correct way to get it with the help of this one.
Thank you.
EDIT
I found this digging around old code. Might be helpful to anyone.
So the full query:
String[] PROJECTION = new String[] { ContactsContract.RawContacts._ID,
ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.PHOTO_ID,
Email.DATA, ContactsContract.CommonDataKinds.Photo.CONTACT_ID };
String order = " CASE WHEN " + ContactsContract.Contacts.DISPLAY_NAME
+ " NOT LIKE '%#%' THEN 1" + " ELSE 2 END, "
+ ContactsContract.Contacts.DISPLAY_NAME + " COLLATE NOCASE";
String filter = Email.DATA + " NOT LIKE '' ) GROUP BY ( " + Email.DATA;
then its
getContentResolver().query( Email.CONTENT_URI, PROJECTION, filter, null, order);
When you want to access the photo of a contact, you need to specify the contact photo URI, for example using this method:
public Uri getContactPhotoUri(long contactId) {
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
photoUri = Uri.withAppendedPath(photoUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
return photoUri;
}
But for contactId you must use:
String id = ContactsContract.CommonDataKinds.Photo.CONTACT_ID;
long contactId = Long.parseLong(id);
Please note that a common error is to use ContactsContract.Contacts._ID instead ContactsContract.CommonDataKinds.Photo.CONTACT_ID
I hope that can help you.
You should use RAW_CONTACT_ID in the query. For ex, there can be two different contacts i.e. different RAW_CONTACT_ID for a single CONTACT_ID.
maybe you can take a look at this blog post in the example there they query all contacts, email addresses and the contact photo
http://blog.app-solut.com/2011/03/working-with-the-contactscontract-to-query-contacts-in-android/
best code will be
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Id);
Bitmap photoBitmap;
ContentResolver cr = getContentResolver();
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(cr, photoUri);
photoBitmap = BitmapFactory.decodeStream(is);
it works for all