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.
Related
mGetContent =
registerForActivityResult(new ActivityResultContracts.GetContent(),
uri -> {
if(uri!=null) {
noticeUri = uri;
textViewNoticeName.setText(uri.getPath());
}
else{
Toast.makeText(CROption.this, "No file selected", Toast.LENGTH_SHORT).show();
}
});
Launching picker like this:
mGetContent.launch("application/pdf");
It's working in android 10. But in android 7(emulator), it is showing wrong path like this
Choosing this file
Getting path like below:
I can read file size and can also upload the file in cloud storage. But I can't read the file name , file type and correct path.
haven't taken storage permission.
I want to allow user to select a pdf file for uploading. I need the file name and type for this.
I haven't worked in storage before.
Get file name like this:
Cursor returnCursor =
getContentResolver().query(uri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
textViewNoticeName.setText(returnCursor.getString(nameIndex)));
You can get filetype like this:
String mime=getContentResolver().getType(uri);
I am extracting audio files and showing in the recyclerview.
I have given delete option after pressing delete button the file is removed from the list and from the file manager but when I reopen the app the audio file appears again at the same place in recycler view but it doesn't play.
But when I recheck the file manager the file is not there and then I cleared the cache and storage but file is still there.
So I reinstall the app but that file is still there but you cannot play it.
And if you delete the file directly from file manager the file doesn't appear in the app instantly.
val uri = Uri.parse(getSongsList?.get(item.groupId)?.songData)
val fdelete = File(uri.path)
if (fdelete.exists()) {
Log.e("v", "fscsg")
if (fdelete.delete()) {
Log.e("vdv", "fg")
System.out.println("file Deleted :${uri.path}")
} else {
Log.e("vd", "fgcs")
System.out.println("file not Deleted :${uri.path}")
}
}
Log.i("ld", getSongsList?.get(0)?.songTitle + " " + item.groupId)
getSongsList?.removeAt(item.groupId)
_mainScreenAdapter?.notifyDataSetChanged()
So how it could be possible that when file is not there in the storage still it is appearing in the app.
File file = new File(uriOfFile);
boolean deleted = file.delete();
//delete file from Media Database
scanaddedFile(file);
private void scanaddedFile(String path) {
try {
MediaScannerConnection.scanFile(context, new String[] { path },
null, new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
context.getContentResolver()
.delete(uri, null, null);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
I got the answer it was very frustrating.
There is a media database which hold all the information regarding the media file so when I delete the file it is deleted but still have record in media database and content resolver takes the data from media database hence it is there in the app.
So if we restart the phone then the deleted file is gone from the list so every time we have to delete the file we have to delete it from database record also.
Still looking for how to delete from media database.
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.
Before marking this question as duplicate i wanna say that i had visited many similar questions but none of them had solved my problem.So, i had extracted all audio files from internal storage using MediaStore and stored its Uri in string form but later when i try to use file.delete using that Uri to delete the audio, former is returning false.
Following goes the code for extracting song uri and its working properly:
Uri uri= MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection=MediaStore.Audio.Media.IS_MUSIC+"!=0";
Cursor c=getContentResolver().query(uri,null,selection,null,null);
if(c!=null)
{
c.moveToFirst();
do {
String audioName=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
String artist=c.getString(c.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String album=c.getString(c.getColumnIndex(MediaStore.Audio.Media.ALBUM));
String url=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
String size=c.getString(c.getColumnIndex(MediaStore.Audio.Media.SIZE));
audioInfoArrayList.add(new AudioInfo(url,audioName,artist,album));
}while (c.moveToNext());
c.close();
Here, i had stored all the retrieved information about audio in arrayList of a custom type which also stores above extracted uri in string form which could be extracted using getUrl() method.
Following goes the code how i'am trying to delete it:
Uri uri= Uri.parse(audioInfo.get(position).getUrl()); //its actually returning the url stored above in string form
deleteFile(uri.getPath());
Log.i("logText","uri.getPath() : "+uri.getPath());
Log.i("logText","audioInfo.get(position).getUrl() : "+audioInfo.get(position).getUrl());
deleteFile function:
public void deleteFile(String filePath){
if(filePath.startsWith("content://")){
ContentResolver contentResolver = context.getContentResolver();
contentResolver.delete(Uri.parse(filePath), null, null);
}else {
File file = new File(filePath);
if(file.exists()) {
if (file.delete()) {
Log.e("logText", "File deleted."); //condition 0
}else {
Log.e("logText", "Failed to delete file!"); //condition 1
}
}else {
Log.e("logText", "File not exist!"); //condition 2
}
}
}
And finally my logcat for a sample audio file:
01-11 13:52:34.257 19982-19982/com.example.hp.myplayer E/logText: Failed to delete file!
01-11 13:52:34.257 19982-19982/com.example.hp.myplayer I/logText: uri.getPath() : /storage/emulated/0/bluetooth/Copy Copy Fireflies-Owl_City[www.Mp3MaD.Com].mp3
01-11 13:52:34.257 19982-19982/com.example.hp.myplayer I/logText: audioInfo.get(position).getUrl() : /storage/emulated/0/bluetooth/Copy Copy Fireflies-Owl_City[www.Mp3MaD.Com].mp3
Note: On calling deleteFile() condition 1 is executed not 2 or 0 which according to me means that file is being located using that uri in the storage but can't be deleted and file.delete() is returning false.
Requesting for read and write external storage permission in manifest is not enough for Android 6 and above.
You should add code to ask the user of your app to confirm the requested permissions.
Google for runtime permissions.
I have an idea for an app, and to do it i need to be in the folder where the stock camera stores it's pictures. But since most manufactureres name the folder inside DCIM diferently, is there a way to find the specific folder that the camera saves pictures into. Also I can't list and open the first result because, for example i have 5 folders in there. Thanks!
One of the solution is to insert photo to MediaStore using ContentResolver (it will create empty JPG file), retrieve its path and delete it from MediaStore (file will be deleted as well).
public static File getPhotoDirPath(ContentResolver cr)
{
try
{
Uri takenPhotoUri=cr.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues( 1 ) );
if ( takenPhotoUri == null )
return null;
String photoFilePath=null;
Cursor cursor = cr.query( takenPhotoUri, new String[] { MediaColumns.DATA }, null, null, null );
if ( cursor != null )
{
int dataIdx = cursor.getColumnIndex( MediaColumns.DATA );
if (dataIdx>=0&&cursor.moveToFirst())
photoFilePath = cursor.getString( dataIdx );
cursor.close();
}
cr.delete( takenPhotoUri, null, null );
if (photoFilePath!=null)
return new File(photoFilePath).getParentFile();
return null;
}
catch (Exception ex)
{//insert or delete failed
return null;
}
}
Note that in some cases (the same as when camera apps are not able to save photos) photos may not be inserted successfully eg. SD card is removed (if device cannot emulate external storage), external storage is mounted read-only or some directory in path is write protected etc.
So i ended up doing it with .exists()
String abcd = "is it working ?";
File pathimg = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File testimg = new File (pathimg, "100MEDIA/");
if (testimg.exists()){abcd = testimg.toString();}
else {
File testimg2 = new File (pathimg, "100ANDRO/");
if (testimg2.exists()){abcd = testimg2.toString();}
else {
File testimg3 = new File (pathimg, "Camera/");
if (testimg3.exists()){abcd = testimg3.toString();}
else {
File testimg4 = new File (pathimg, "100LGDSC/");
if (testimg4.exists()){abcd = testimg4.toString();}
else {
abcd = "It's not working";
}
}
}
}
On my G2 with the folder "100LGDSC" it's working.
you may take Environment.DIRECTORY_PICTURES as the valid directory.
The following will refer to that directory (but it is not guaranteed in all devices):
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);