I have this app installed in my device (Nexus s).
It caches some images if you use this app. This is why it shows cached images in my device's gallery.
I use cursor to get the path
final String[] columns = { MediaStore.Images.Media.DATA };
Cursor imagecursor = managedQuery(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns,
MediaStore.Images.Media._ID + " = " + id, null, MediaStore.Images.Media._ID);
if (imagecursor != null && imagecursor.getCount() > 0){
imagecursor.moveToPosition(0);
String path = imagecursor.getString(imagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
Log.d("path", path);
File f = new File("file://" + path);
Log.d("check_file", "" + f.exists());
}
I get the path:
/mnt/sdcard/cache/hk.ignition.podcast/cartoon/2/http%3A%2F%2Fbigcity.learnenglishapps.com%2Fimages%2Fcartoons%2Fset2%2Ffast-food-new-1.png
Downloaded image is:
http://bigcity.learnenglishapps.com/images/cartoons/set2/fast-food-new-1.png
When I pull the file or explore it with file manager like Astro, its there.
But when I check if file exist, then it says false.
Is there any character issue?
Update:
Removing file:// worked to check if file exist.
Next is, I'd like to open that file in gallery.
should I use this path to open image?
But that not worked:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file:///mnt/sdcard/cache/hk.ignition.podcast/cartoon/2/http%3A%2F%2Fbigcity.learnenglishapps.com%2Fimages%2Fcartoons%2Fset2%2Ffast-food-new-1.png"),
"image/*");
startActivityForResult(intent, 3);
Or I should try to get content:// style path from MediaStore?
Update 2:
Solved using :
Uri.fromFile(f);
Instead of Uri.Parse(). As it builds / character from encode format.
Change new File("file://" + path) to just new File(path)
Related
I am trying to get WhatsApp profile photos and i am getting photoUri for all my contacts that have WhatsApp.
but when am trying to present the photoUri i am getting the following exception:
W/ImageView: Unable to open content: content://com.android.contacts/raw_contacts/12/display_photo
java.io.FileNotFoundException: No photo file found for ID 0
I add a code to check if the file is existing or not and i have found that the file is existing, so it is not clear why i am getting the above exception.
here is the code that i am using to get the photo URI:
public Uri getPhotoUri(long contactId) {
Uri photoUri=null;
ContentResolver contentResolver = getContext().getContentResolver();
Cursor photoCur = contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI,null,
ContactsContract.RawContacts.CONTACT_ID + "=" + contactId + " AND " +
ContactsContract.RawContacts.ACCOUNT_TYPE + "= ?",
new String[]{"com.whatsapp"}, ContactsContract.RawContacts.CONTACT_ID);
if (photoCur != null && photoCur.moveToFirst()) {
Uri photoId = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactId);
photoUri = Uri.withAppendedPath(photoId, ContactsContract.RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
}
return photoUri;
}
here is the code that i am using to check if the file exists or not:
if (customer.getContactPhotoUri() != null) {
String fullPath = customer.getContactPhotoUri().toString();
File path = new File(fullPath);
if (path.exists()) {
Log.i("ZCF", "File Exists: " + fullPath);
imageView.setImageURI(customer.getContactPhotoUri());
} else {
Log.i("ZCF", "File does not Exists: " + fullPath);
imageView.setImageDrawable(context.getDrawable(R.drawable.ic_person_blue_24dp));
}
} else {
imageView.setImageDrawable(context.getDrawable(R.drawable.ic_person_blue_24dp));
}
the result of this code is:
I/ZCF: File Exists:
content://com.android.contacts/raw_contacts/12/display_photo
Whatsapp doesn't store its contact photos using ContactsContract, so you can't access them.
The photos are stored within Whatsapp's folder on your internal memory drive, you can see them manually using a file-explorer app, but these folders are not accessible to apps, so you can't access them programatically.
This is obviously intentional, as Whatsapp doesn't want their photos to be leaked out outside of their app.
Android 7.0, API 24. Permissions are granted in both AndroidManifest and real time.
Following are the scenarios which I have tried:
Only using the content resolver removes it from MediaStore but it comes back when the device is restarted.
When deleting an internal image "/storage/emulated/0/DCIM/Camera/..."
it works, but when trying to delete an external image (or what should
be external image) "/storage/4ED7-7F17/DCIM/Camera/..." it fails at
file.canWrite().
Using Environment.getExternalStorageDirectory().getAbsolutePath() returns "/storage/emulated/0" (+ "/DCIM/Camera/...") and it fails at file.exists().
Hardcoding "/SD card/DCIM/Camera/..." (which should be the correct filepath) fails at file.exists().
Weirdly, in the Android Device File Explorer, the files that should be in the SD Card folder are in the "/storage/4ED7-7F17/" folder which the files have a permission listing of -rwxrwx--x. And permission inside "/storage/emulated/" is "Permission denied". But to find the files in Android app MyFiles or Windows File Explorer the files are in "/SD card/DCIM/Camera/...".
Completely confused any help would be greatly appreciated.
File file = new File(filename);
if (file.exists()) {
if (file.canWrite()) {
if (file.delete()) {
// Set up the projection (we only need the ID)
String[] projection = {MediaStore.Files.FileColumns._ID};
// Match on the file path
String selection = MediaStore.Files.FileColumns.DATA + " = ?";
String[] selectionArgs = new String[]{filename};
Uri queryUri;
if (isVideo) {
// Query for the ID of the media matching the file path
queryUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else {
// Query for the ID of the media matching the file path
queryUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
ContentResolver contentResolver = context.getContentResolver();
Cursor c = contentResolver.query( queryUri, projection, selection, selectionArgs, null);
if (c.moveToFirst()) {
// We found the ID. Deleting the item via the content provider will also remove the file
long id = c.getLong(c.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID));
Uri deleteUri = ContentUris.withAppendedId(
MediaStore.Files.getContentUri("external"), id);
contentResolver.delete(deleteUri, null, null);
} else {
// File not found in media store DB
Toast.makeText(context, "File not found: " + filename,
Toast.LENGTH_LONG).show();
}
c.close();
Toast.makeText(context, "File deleted: " + filename,
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "File not deleted: " + filename,
Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(context, "File cannot be wrote to: " + filename,
Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(context, "File does not exist: " + filename,
Toast.LENGTH_LONG).show();
}
}
) "storage/4ED7-7F17/DCIM/Camera/..." it fails at file.canWrite().
Yes of course. Micro SD cards are read only on modern Android systems.
Apps nowadays can only write in one app specific directory on SD card.
If you want write access to the whole card you need to use the Storage Access Framework.
I stand correct. What's missing on N is MediaStore.getDocumentUri(Context context, Uri mediaUri), which provides conversion of fictitious file paths for the DCIM directory on Oreo+ to a Storage Access Framework URI that can be used to delete the file. N doesn't seem to provide an equivalent that I can find. And the content: Uris for media files don't work with Storage Access Framework unless converted.
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.
My app intends to launch a file using ACTION_VIEW.
The following code returns the file path of the selected file
if(Intent.ACTION_VIEW.equals(action)){
String Path = intent.getDataString();
//file processing code
}
It works fine when the selected file has no spaces in it. e.g Path becomes "/mnt/sdcard/sample.pdf" , but when i select a file with spaces in it's name such as "/mnt/sdcard/4C 1099 + 2 WOOO6.pdf" Path becomes "/mnt/sdcard/4C%20%20%201099%20%20%20%2B%20%202%20W0006.pdf"
Any help?
if(Intent.ACTION_VIEW.equals(action)){
Uri uri = intent.getData();
path = uri.getPath();
path = path.replace("%20", " ");
}
I'm trying to figure out how to convert an Android Uri to a Java URI. What I'm trying to do is get a File, but as far as I can tell, I need to pass it a Java URI.
Here's my Uri that I'm attempting to convert:
content://media/external/images/media/100
And what I'm attempting to get at:
File mediaFile = new File(new URI("android.net.Uri"));
Where "android.net.Uri" is my Uri object
If there is a different/better way to get a java.io.File object from this content Uri, I'm open to suggestions as I've searched far and wide with no luck so far.
Got it figured out, I was able to get the real filepath of the Uri and then create the File:
Uri uri = Uri.parse("content://media/external/images/media/47");
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cur = managedQuery(uri, projection, null, null, null);
cur.moveToFirst();
String path = cur.getString(cur.getColumnIndex(MediaStore.Images.Media.DATA));
mediaFile = new File(path);