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.
Related
when I get file path of file in Android 11 .
protected File getOutputMediaFile() {
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date());
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, timeStamp + ".jpg");
fileUri = getActivity().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Log.e("File Uri Path", "Uri inserted into media store = " + fileUri);
Toast.makeText(getActivity(), "File uri = "+fileUri, Toast.LENGTH_LONG).show();
String path = getImageRealPathFromURI(fileUri);
File file = new File(path);
return file;
}
private String getImageRealPathFromURI(Uri contentUri) {
String realPath = "";
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = getActivity().getContentResolver().query(contentUri, proj, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
realPath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
} else {
Log.e("Image Real Path", "Cursor count appearing to be zero");
Toast.makeText(getActivity(), "Cursor count appearing to be zero", Toast.LENGTH_LONG).show();
realPath = "";
}
} catch (Exception e) {
Log.e("Image Real Path", "Exception fetching getImageRealPathFromURI() due to " + e.toString());
Toast.makeText(getActivity(),"Exception fetching getImageRealPathFromURI() due to "+e.toString(), Toast.LENGTH_LONG).show();
realPath = "";
} finally {
cursor.close();
}
return realPath;
}
I meet error : /storage/emulated/0/Pictures/1614237849822.jpg: open failed: EEXIST (File exists).
at libcore.io.IoBridge.open(IoBridge.java:492).
When I getOutputMediaFile().getpath.
Anyone help me?
add this line in manifest file :
android:requestLegacyExternalStorage="true"
and make sure that you add Read external storage permission and also allow this permission
The getContentResolver().insert() will give you a nice fresh uri to write the content of a file to.
It gives an uri you can use. It does not create a file for you.
Even if you get the path of the yet non existing file with the .DATA column, that file does not exist yet.
You can simply check that with File.exists().
Only if you open an OutputStream for the obtained uri and write to it the file will be created.
Use the uri! For what do you need that data path?
You can use this type to set mMediaRecoder's path:
final ParcelFileDescriptor parcelFileDescriptor = mContext.getContentResolver().
openFileDescriptor(Uri.parse(mVideoProfile.path), "rw");
mMediaRecorder.setOutputFile(parcelFileDescriptor.getFileDescriptor());
mVideoProfile.path = "content://media/external/video/media/751";
I am writing a camera and gallery app, following the official Google documentation. The problem is that it mostly focuses on how to take a picture and how to save it in memory. I am saving them in the application external memory through getExternalFilesDir().
What I am now trying to do is simpy query that directory in which taken photos are saved, through MediaStore, in order to display all the pictures in there in a recycler view. But I can't seem to find anywhere an explanation on how to do the retrieval. There is something wrong with the Uri that I probably didn't understand well, and I don't know how to solve. Even in here https://developer.android.com/training/data-storage/files#PrivateFiles the article only talks about saving files in the various storage options, but not about retrieving them.
Here is the code of how I save the files:
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
return image;
}
This is the function that actually sends the intent (and then onActivityResult handles the returned data):
private void dispatchTakePictureIntent() {
final String TAG = "dispatchTakePic: ";
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
Log.e(TAG, "Error while creating a file");
ex.printStackTrace();
}
// Continue only if the File was successfully created
// Authority has to be exactly like in manifest
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(
this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
This is the code where I'm trying to get the information about the photos taken:
private void populatePhotoArray() {
final String TAG = "popPhotoArray: ";
ContentResolver contentResolver = getContentResolver();
String photo_id, photo_title, photo_path = "";
final String[] PHOTOGRAPHS_PROJECTION = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.TITLE,
MediaStore.Images.Media.DATA};
File photographsDirectory = getExternalFilesDir(Environment.DIRECTORY_MOVIES);
Uri photographsUri = Uri.fromFile(photographsDirectory);
//Uri photographsUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
//Uri photographsUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC";
final Cursor cursor = contentResolver.query(
photographsUri,
PHOTOGRAPHS_PROJECTION,
null,
null,
sortOrder);
Log.d(TAG, "created the projection");
if (cursor != null && cursor.getCount() > 0) {
while (cursor.moveToNext()) {
photo_id = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID));
photo_title = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.TITLE));
photo_path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
// save to photo list
applicationPhotosList.add(new Photographs(photo_id, photo_title, photo_path));
Log.d(TAG, "new photo added");
}
cursor.close();
Log.d(TAG, "Photo array filled up");
}
else if (cursor == null){
Log.d(TAG, "No photos present, cursor is null");
Toast.makeText(this, "No photos present", Toast.LENGTH_SHORT).show();
}
Looks like trying to transform the path of getExternalFileDir() into an Uri doesn't work. The cursor is empty. But MediaStore only has MediaStore.Images.Media.EXTERNAL_CONTENT_URI and that's not suitable as that queries the whole device memory, while I only need that particular directory in which my app is saving the pictures taken. What am I missing? It cannot be that hard, right?
There is another way to retrieve the images from a specific folder w/o using the cursor and I think its more faster.
private fun getAllShownImagesPath(): ArrayList<String> {
var filePath: ArrayList<String> = ArrayList<String>()
val path = File(getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).path, "BacFo Camera")
if (path.exists()) {
for (i in path.list().iterator()) {
filePath?.add("" + path.toString() + "/" + i)
}
}
return filePath!!
}
`
In "fileNames" you have the path of all images or videos whatever you have saved in the specific folder
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 trying to get the path of the video file for a video thumbnail. I'm not sure why it is still coming as null after I modified based on some solutions here. The version of android is 6.0.1.
The user clicks the floating action button and summons a gallery of videos.
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.addNote);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Video"), REQUEST_TAKE_GALLERY_VIDEO);
}
});
When the user selects a desired video from the gallery, the video goes to the activity which it'll be sorted out.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
Log.d(TAG, "Uri: " + uri);
Log.d(TAG, "Uri authority: " + uri.getAuthority());
String filemanagerstring = uri.getPath();
Log.d(TAG, "filemanagerstring: " + filemanagerstring);
String selectedImagePath = getPath(uri);
Log.d(TAG, "selectedImagePath: " + selectedImagePath);
}
}
The method to get the path of the video file.
public String getPath(Uri uri) {
Cursor cursor = this.getContentResolver().query(uri, null, null, null, null);
int idx = 0;
//Source not from device capture or selection
if (cursor == null) {
return uri.getPath();
} else {
cursor.moveToFirst();
idx = cursor.getColumnIndex(MediaStore.Video.VideoColumns.DATA);
if (idx == -1) {
Log.d(TAG, "uri path: " + path);
return uri.getPath();
}
}
String path = cursor.getString(idx);
Log.d(TAG, "path: " + path);
cursor.close();
return path;
}
Results: I got the null (-1) and got the uri's path, that's not the correct path. I need the full path of the video file.
Uri: content://com.android.providers.media.documents/document/video%3A6174
Uri authority: com.android.providers.media.documents
filemanagerstring: /document/video:6174
**uri path: 16842794**
selectedImagePath: /document/video:6174
and summons a gallery of videos
No, it does not. It allows the user to choose from any activity that supports ACTION_GET_CONTENT for a MIME type of video/*. The Uri that you get back can be from anything, not necessarily a "gallery" app, and not necessarily one that points to a file. The Uri could point to:
A file on external storage, one that you might be able to read directly
A file on removable storage, which you cannot access
A file on internal storage of some other app
The contents of a BLOB column in a database
Something that has to be decrypted on the fly
Something that does not yet exist on the device and needs to be downloaded
And so on
The method to get the path of the video file
The only values you can get back from that query(), reliably, are the OpenableColumns, for the size and "display name" of the content.
You need to either:
Use a thumbnail engine that accepts a content Uri as a parameter, or
Use ContentResolver and openInputStream() to get an InputStream on the content, then use some thumbnail engine that accepts an InputStream as a parameter, or
Use ContentResolver and openInputStream() to get an InputStream on the content, then use that stream to make your own file that contains a copy of the bytes from the content, so you can use your own file with some thumbnail engine that requires a file, or
Do not use ACTION_GET_CONTENT, but instead render your own "chooser" UI by asking the MediaStore for all videos, as you can get thumbnails of those videos from MediaStore (see this sample app)
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)