I have been reading the android documentation and I can't find a solution to delete multiple files without multiple dialogs in Android 10 (API Level 29)
I found the following in the Android documentation:
This is very frustrating not only for me but for every user who has API level 29, because there are some use cases where up to 100+ files must be deleted.
Entry Point when wanting to delete media
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
deleteMediaR(activity, uris)
}
Build.VERSION.SDK_INT == Build.VERSION_CODES.Q -> {
deleteMediaQ(activity, uris)
}
else -> {
deleteMediaDefault(activity, uris)
}
Above API Level 29
@RequiresApi(Build.VERSION_CODES.R)
private fun deleteMediaR(activity: Activity, uris: ArrayList<String>) {
val contentResolver = activity.contentResolver
val collection: ArrayList<Uri> = ArrayList()
collection.addAll(uris.map { uri -> Uri.parse(uri) })
val pendingIntent = MediaStore.createDeleteRequest(contentResolver, collection)
activity.startIntentSenderForResult(
pendingIntent.intentSender, 42, null, 0, 0, 0, null)
}
API Level 29
@RequiresApi(Build.VERSION_CODES.Q)
private fun deleteMediaQ(activity: Activity, uris: ArrayList<String>) {
try {
deleteMediaDefault(activity, uris)
} catch (exception: Exception) {
if (exception is RecoverableSecurityException) {
val pendingIntent: PendingIntent = exception.userAction.actionIntent
activity.startIntentSenderForResult(pendingIntent.intentSender,
42, null, 0, 0, 0, null)
}
}
}
Below API Level 29
contentResolver.delete(uri, where, media))
This is a very frustrating problem only concerning Android 10. I'm assuming Google forgot to implement this feature into their API. However, I'm hoping there is a proper solution as this breaks the app when using Android 10.
You can do it 2 ways, actually.
1. Using mediastore :
You can easily delete any media file using Mediastore delete API like this,
ActivityResultLauncher<IntentSenderRequest> deleteLauncher
= registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == RESULT_OK) {
// Media files deleted successfully. Do your stuff.
}
}
});
@RequiresApi(api = Build.VERSION_CODES.R)
private void deleteAPI30(ArrayList<Media> mediaList, Context context) throws IntentSender.SendIntentException {
ContentResolver contentResolver = context.getContentResolver();
List<Uri> uriList = new ArrayList<>();
for (int i = 0; i < mediaList.size(); i++) {
uriList.add(mediaList.get(i).getAppendedIdUri());
}
Collections.addAll(uriList);
PendingIntent pendingIntent = MediaStore.createDeleteRequest(contentResolver, uriList);
IntentSenderRequest senderRequest = new IntentSenderRequest.Builder(pendingIntent.getIntentSender())
.setFillInIntent(null)
.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 0)
.build();
deleteLauncher.launch(senderRequest);
}
P.S. You need to get the directory access permission using SAF directory chooser if things don't go off easy.
2. Deleting using storage access framework (SAF) :
public void deleteMediaSAF(ArrayList<Media> mediaList) {
DocumentFile documentFile = DocumentFile.fromTreeUri(this, getContentResolver().getPersistedUriPermissions().get(0).getUri());
for (int i = 0; i < mediaList.size(); i++) {
File file = new File(mediaList.get(i).getPath());
DocumentFile nextDocument = documentFile.findFile(file.getName());
try {
DocumentsContract.deleteDocument(getContentResolver(), nextDocument.getUri());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
mediaList = loadMedia(DIR_NAME);
adapter.setMediaList(mediaList);
adapter.notifyDataSetChanged();
adapter.deselectAll();
if (mediaList.size() > 0) {
hideEmptyView();
} else {
showEmptyView();
menuItem.setVisible(false);
}
}
You can use these methods at for different APIs at the same time if possible. For an instance, using Mediastore API for Android 11 & above and using SAF API for Android 10.