Got the solution
There are two possibility for getting hidden files access in android 11
- give MANAGE_EXTERNAL_STORAGE permission as said by @Subarata Talukder
- give particular folder access permission using storage manager as explained below (without using MANAGE_EXTERNAL_STORAGE permission)
Here I am showing how to access whatsapp statuses programmatically
//give permissions in manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
//give run time permissions
static final int REQUEST_PERMISSION_KEY = 1;
int REQUEST_ACTION_OPEN_DOCUMENT_TREE = 101;
SharedPreferences sharedPreferences;
check if run time permissions are given or not on button click
if(sharedPreferences.getString("WATREE","").equals("")){
if(checkAndRequestPermissions()){
if (SDK_INT >= Build.VERSION_CODES.Q) {
askPermission();
}else {
callActivity();
}
}
}else{
callActivity();
}
private boolean checkAndRequestPermissions() {
int writePerm = ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
int readPerm = ContextCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.READ_EXTERNAL_STORAGE);
List<String> listPermissionsNeeded = new ArrayList<>();
if (writePerm != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if(readPerm != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(GBV_StartActivity.this,
listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),
REQUEST_PERMISSION_KEY);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION_KEY) {
try {
Map<String, Integer> permsLogin = new HashMap<>();
// Initialize the map with both permissions
permsLogin.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
permsLogin.put(Manifest.permission.READ_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
permsLogin.put(permissions[i], grantResults[i]);
// Check for both permissions
if (permsLogin.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& permsLogin.get(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (SDK_INT >= Build.VERSION_CODES.Q) {
askPermission();
}else {
callActivity();
}
// process the normal flow
//else any one or both the permissions are not granted
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|| shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) {
showDialogOK((dialog, which) -> {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
break;
}
});
}
//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
Toast.makeText(getApplicationContext(), "Go to settings and enable permissions.", Toast.LENGTH_LONG)
.show();
finish();
//proceed with logic by disabling the related features or quit the app.
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void showDialogOK(DialogInterface.OnClickListener okListener) {
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(GBV_StartActivity.this);
alertDialogBuilder.setMessage("You need to allow access to the permissions.")
.setCancelable(false)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener);
android.app.AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
public void callActivity(){
startActivity(new Intent(GBV_StartActivity.this, MainActivity.class));
}
private String getWhatsupFolder() {
String oldPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/.Statuses";
String oldBusinessPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp Business/Media/.Statuses";
String newPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/media/com.whatsapp/WhatsApp/Media/.Statuses";
String newBusinessPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/media/com.whatsapp.w4b/WhatsApp Business/Media/.Statuses";
String finalPath;
if(new File(newBusinessPath).exists()){
finalPath = "Android%2Fmedia%2Fcom.whatsapp.w4b%2FWhatsApp Business%2FMedia%2F.Statuses";
}else if(new File(newPath).exists()){
finalPath = "Android%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses";
}else if(new File(oldBusinessPath).exists()){
finalPath = "WhatsApp Business%2FMedia%2F.Statuses";
}else {
finalPath = "WhatsApp%2FMedia%2F.Statuses";
}
return finalPath;
}
@RequiresApi(Build.VERSION_CODES.Q)
private void askPermission() {
StorageManager storageManager = (StorageManager) getSystemService(STORAGE_SERVICE);
Intent intent = storageManager.getPrimaryStorageVolume().createOpenDocumentTreeIntent();
String targetDirectory = getWhatsupFolder(); // add your directory to be selected by the user
Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI");
String scheme = uri.toString();
scheme = scheme.replace("/root/", "/document/");
scheme += "%3A"+targetDirectory;
uri = Uri.parse(scheme);
Log.w("TAG", "askPermission: uri::"+uri );
intent.putExtra("android.provider.extra.INITIAL_URI", uri);
startActivityForResult(intent, REQUEST_ACTION_OPEN_DOCUMENT_TREE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == this.REQUEST_ACTION_OPEN_DOCUMENT_TREE && resultCode == -1) {
Uri data = intent.getData();
try {
getContentResolver().takePersistableUriPermission(data, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} catch (Exception e) {
e.printStackTrace();
}
SharedPreferences.Editor editor2 = sharedPreferences.edit();
editor2.putString("WATREE", data.toString());
editor2.apply();
callActivity();
}
}
now after giving all permissions try to get images or videos from storage like below:
if (SDK_INT >= Build.VERSION_CODES.Q) {
DocumentFile[] allFiles = getFromSdcard();
if (allFiles != null) {
for(int i = 0 ; i <allFiles.length ; i++){
if (!allFiles[i].getUri().toString().contains(".nomedia")) {
Log.e("path:",allFiles[i].getUri().toString());
//add data in your arraylist
}
}
}
}else {
String oldPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/.Statuses";
String oldBusinessPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp Business/Media/.Statuses";
String newPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/media/com.whatsapp/WhatsApp/Media/.Statuses";
String newBusinessPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/media/com.whatsapp.w4b/WhatsApp Business/Media/.Statuses";
String finalPath;
if (!new File(oldPath).exists()) {
if (!new File(oldBusinessPath).exists()) {
if (!new File(newPath).exists()) {
if (!new File(newBusinessPath).exists()) {
finalPath = oldPath;
} else {
finalPath = newBusinessPath;
}
} else {
finalPath = newPath;
}
} else {
finalPath = oldBusinessPath;
}
} else {
finalPath = oldPath;
}
File file2 = new File(finalPath);
if (file2.exists()) {
File[] listFiles = file2.listFiles();
if (listFiles != null) {
for (int i = 0; i < listFiles.length; i++) {
Log.e("path:",listFiles[i].getPath()+"");
//add data in your arraylist
}
}
}
}
public DocumentFile[] getFromSdcard() {
DocumentFile fromTreeUri = DocumentFile.fromTreeUri(getContext(), Uri.parse(sharedPreferences.getString("WATREE","")));
if (fromTreeUri == null || !fromTreeUri.exists() || !fromTreeUri.isDirectory() || !fromTreeUri.canRead() || !fromTreeUri.canWrite()) {
return null;
}
return fromTreeUri.listFiles();
}