To support Android 11 storage, I have implemented Scoped Storage - MediaStore API successfully. However, I ended up with one scenario which I am not sure how to resolve. Scenario is, When the Application is launched for the first time, we have created the Folder under Documents folder and able to read and write files into this folder without creating any duplicate folders. However, If I do Clear Data and re-login the Application, I am not able to fetch the folder which is already created and each time it is creating a new folder with duplicate name - Suffix as (2), (3) etc..,
Please find my code which I tired and also find the screenshots.
File folder = null;
String folderName = "Duration";
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
Uri contentUri = MediaStore.Files.getContentUri("external");
String filePath = FileUtils.readFileExternalStorage(contentUri,context,folderName).getPath();
if (!TextUtils.isEmpty(filePath) && FileUtils.isFileExisting(filePath)) {
folder = new File(filePath);
} else {
Uri uri = FileUtils.createFileExternalStorage(contentUri,context,folderName),Environment.DIRECTORY_DOCUMENTS);
Commons.print("URI "+uri.getPath());
folder = new File(FileUtils.getPath(context,uri));
}
if (!folder.exists()) {
folder.mkdirs();
}
} else {
folder = getStorageDir(folderName);
bmodel.deleteFiles(getStorageDir(folderName) + "/", filename);
}
File file = new File(folder, filename );
if(file.exists()) {
file.delete();
}
if (SynchronizationHelper.bcpJSONData != null) {
FileOutputStream outputStream;
try {
Commons.print("FilePath " + file.getPath());
outputStream = new FileOutputStream(file);//context.openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(SynchronizationHelper.bcpJSONData.getBytes());
outputStream.close();
outputStream = null;
SynchronizationHelper.bcpJSONData = null;
} catch (Exception e) {
e.printStackTrace();
}
}
This is FileUtils class:
@RequiresApi(api = Build.VERSION_CODES.Q)
public static File readFileExternalStorage(Uri contentUri, Context context, String filename) {
final String selection = MediaStore.Files.FileColumns.DISPLAY_NAME + "=?";
final String[] selectionArgs = new String[] {filename};
return new File(getDataColumn(context,contentUri,selection,selectionArgs));
}
@RequiresApi(api = Build.VERSION_CODES.Q)
public static Uri createFileExternalStorage(Uri contentUri, Context context, String filename, String folder) {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, folder);
return context.getContentResolver().insert(contentUri, values);
}
public static String getDataColumn(Context context, Uri uri,
String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return "";
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] { split[1] };
return getDataColumn(context, contentUri, selection,
selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return "";
}
On every instance after clearing data of the application, this method getDataColumn() is returning "" empty and on Debugging I found that the Cursor inside the try block, is not fetching anything out of it.
