Is it possible to get WhatsApp media file using MediaStore.VOLUME_EXTERNAL

Viewed 2489

My app requires a feature that backups WhatsApp status, voice notes, and images. As you know after Android Q google enforcing to access external media files using MediaStore API.

WhatsApp also moved their file to /Android/media/com.whatsapp/WhatsApp. I tried using MANAGE_EXTERNAL_STORAGE permission it works fine, but backing up these files is not the core functionality of the app, so I don't think google going to let me use this permission.

I wonder if there any way to read those files using MediaStore.VOLUME_EXTERNAL?

I tried something like this. I am not sure if this is even possible.

val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)

val selection= (MediaStore.Files.FileColumns.MEDIA_TYPE + "="
        + MediaStore.Files.FileColumns.MEDIA_TYPE_NONE)
val selectionArgs= arrayOf("%/WhatsApp/Media/.Statuses%")
val cursor = applicationContext.contentResolver.query(
    collection, null, selection, selectionArgs, null)
debug(cursor?.columnCount)
cursor?.close()

it throws an exception.

Caused by: android.database.sqlite.SQLiteException: no such column: media_type
1 Answers

Try this...

To read whatsapp status you don't need to do more things, just changed its path.

Also you don't need to use MANAGE_EXTERNAL_STORAGE permission. This can work with older permission too.

BELOW ANSWER FOR SDK 29

This way I have done

String path=Environment.getExternalStorageDirectory().getAbsolutePath()+"/Android/media/"+"com.whatsapp" + "/WhatsApp/Media/.Statuses/"

File directory = new File(wa_path);
    if (!directory.exists()) {
        directory.mkdirs();
    }
    File[] files = directory.listFiles();
    if (files != null) {
        Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
        for (int i = 0; i < files.length; i++) {
            if (!files[i].getName().equals(".nomedia")) {
                your_list.add(files[i]);
            }
        }
    }

This is working in android 11 too. And I only ask for "READ_EXTERNAL_STORAGE" and "WRITE_EXTERNAL_STORAGE" like before.

So now you need to check whether "WhatsApp" folder is available in root storage(before where it was), if not available then need to check in path I mentioned above.

FOR SDK 30 AND ABOVE

First ask for app specific folder permission

    try {
        Intent createOpenDocumentTreeIntent = ((StorageManager) getSystemService("storage")).getPrimaryStorageVolume().createOpenDocumentTreeIntent();
        String replace = ((Uri) createOpenDocumentTreeIntent.getParcelableExtra("android.provider.extra.INITIAL_URI")).toString().replace("/root/", "/document/");
        createOpenDocumentTreeIntent.putExtra("android.provider.extra.INITIAL_URI", Uri.parse(replace + "%3A" + "Android%2Fmedia"));
        startActivityForResult(createOpenDocumentTreeIntent, 500);
    } catch (Exception unused) {
        Toast.makeText(MainActivity.this, "can't find an app to select media, please active your 'Files' app and/or update your phone Google play services", 1).show();
    }

Now in OnActivityResult

    @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == 500) {
                if (data != null) {
     Uri wa_status_uri = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia/document/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses");
 getContentResolver().takePersistableUriPermission(data.getData(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
                    //save shared preference to check whether app specific folder permission granted or not              FastSave.getInstance().saveBoolean(Utils.KEY_IS_APP_SPECTIFIC_PERMISSION_GRANTED, true);
    
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            getDataForAndroid11OnlyStatus(wa_status_uri);
                        }
                    }, 100);
                }
    
            }
        }


//now get status from whatsApp folder

    ArrayList<Object> statusObjectsList = new ArrayList<>();
    
    
    private void getDataForAndroid11OnlyStatus(Uri uriMain) {
        //check for app specific folder permission granted or not
        if (!FastSave.getInstance().getBoolean(Utils.KEY_IS_APP_SPECTIFIC_PERMISSION_GRANTED, false)) {
            //ask for folder permission
        }
    
        Log.d("====", "uriMain ::: " + uriMain);
        ContentResolver contentResolver = getContentResolver();
        Uri uri = uriMain;
        Uri buildChildDocumentsUriUsingTree = DocumentsContract.buildChildDocumentsUriUsingTree(uri, DocumentsContract.getDocumentId(uri));
    
        ArrayList arrayList = new ArrayList();
        Cursor cursor = null;
        try {
            cursor = contentResolver.query(buildChildDocumentsUriUsingTree, new String[]{"document_id"}, (String) null, (String[]) null, (String) null);
            while (cursor.moveToNext()) {
                arrayList.add(DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)));
                if (!DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)).toString().endsWith(".nomedia")) {
    
                    FileHelper fileHelper = new FileHelper(MainActivity.this);
                    String filePath = fileHelper.getRealPathFromUri(DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)));
    
                    statusObjectsList.add(DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)));
    
                }
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //here set your adapter in list and set data from statusObjectsList
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable th) {
            throw th;
        }
    }

Let me know if you didn't understand or not works.

This is working tested in Android 11 emulator, OnePlus Nord, Redmi Note 10 Pro and Poco. In All of these Android 11 device WhatsApp statuses are displaying.

added: So what is the api you targrt I think you target api 29 It will not work if you target api 30 prove your answer

Thank you

Related