Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 10: How to delete MediaStore item and it's associated data on file system programmatically?

I am updating my app to use Scoped Storage feature introduced in Android 10.

My app works with MediaStore and displays images, videos and audio files and provides ability for user to delete item.

What I did earlier to delete file:

  1. Got path from MediaStore.MediaColumns.DATA
  2. Used new File(path).delete() to delete that file
  3. Manually updating MediaStore

Now that MediaStore.MediaColumns.DATA is not available I migrated to deleting items from MediaStore using ContentResolver.delete()

For example I have uri of the item: content://media/external/images/media/502 (its valid uri, I display it's thumbnail in grid). It doesnt matter whether I inserted this item in MediaStore or some other app did.

I use context.getContentResolver().delete(uri, null, null). It either succeeds in deletion (returns 1 row) or catching RecoverableSecurityException to use startIntentSenderForResult() to get access to current uri and then using the same getContentResolver().delete() to delete it in onActivityResult() and then getting successful deletion.

Either way that item is removed from MediaStore and is neither showing in result when I query MediaStore for images, nor in other applications.

BUT this file exists on file system (checked using SAF and various file managers (Google Files, Total Commander))

Sometimes (depends on Android version and media type) these items are brought back to MediaStore after phone reboot (or after opening Google Photos - it scans file system)

For example: Android 10 on my Google Pixel and Google Pixel 3a XL behaves as described above for Images/Video/Audio, but Android 9 on Xiaomi Mi A2 Lite behaves like this only with Audio files, while deleting Images/Video fine.

I have android:requestLegacyExternalStorage="false" in manifest.

Is there a way to force MediaStore to delete data on file system as well? Why is file on file system left behind?

like image 264
artman Avatar asked Mar 16 '20 09:03

artman


People also ask

Does Android 10 have scoped storage?

Scoped storage is the default behavior in Android 10 and 11. Once the app has been whitelisted on Google Play, the user can be asked for special permission. The Media Store in Android 11 has been upgraded.


1 Answers

Use this function to delete file using display name of the file: This func will delete MediaStore item and it's associated data on file system in Android-10 or Android-Q

Note: In my case I am working with files like MediaStore.Files.FileColumns..

public static boolean deleteFileUsingDisplayName(Context context, String displayName) {

    Uri uri = getUriFromDisplayName(context, displayName);
    if (uri != null) {
        final ContentResolver resolver = context.getContentResolver();
        String[] selectionArgsPdf = new String[]{displayName};

        try {
            resolver.delete(uri, MediaStore.Files.FileColumns.DISPLAY_NAME + "=?", selectionArgsPdf);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            // show some alert message
        }
    }
    return false;

}

Use this function to get Uri from DisplayName

public static Uri getUriFromDisplayName(Context context, String displayName) {

    String[] projection;
    projection = new String[]{MediaStore.Files.FileColumns._ID};

    // TODO This will break if we have no matching item in the MediaStore.
    Cursor cursor = context.getContentResolver().query(extUri, projection,
            MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?", new String[]{displayName}, null);
    assert cursor != null;
    cursor.moveToFirst();

    if (cursor.getCount() > 0) {
        int columnIndex = cursor.getColumnIndex(projection[0]);
        long fileId = cursor.getLong(columnIndex);

        cursor.close();
        return Uri.parse(extUri.toString() + "/" + fileId);
    } else {
        return null;
    }

}
like image 129
jazzbpn Avatar answered Sep 28 '22 12:09

jazzbpn