fun getFilePath(context: Context, contentUri: Uri): String? {
try {
val filePathColumn = arrayOf(
MediaStore.Files.FileColumns._ID,
MediaStore.Files.FileColumns.TITLE,
MediaStore.Files.FileColumns.SIZE,
MediaStore.Files.FileColumns.DATE_ADDED,
MediaStore.Files.FileColumns.DISPLAY_NAME,
)
val returnCursor = contentUri.let { context.contentResolver.query(it, filePathColumn, null, null, null) }
if (returnCursor != null) {
returnCursor.moveToFirst()
val nameIndex = returnCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)
val name = returnCursor.getString(nameIndex)
val file = File(context.cacheDir, name)
val inputStream = context.contentResolver.openInputStream(contentUri)
val outputStream = FileOutputStream(file)
var read: Int
val maxBufferSize = 1 * 1024 * 1024
val bytesAvailable = inputStream!!.available()
val bufferSize = min(bytesAvailable, maxBufferSize)
val buffers = ByteArray(bufferSize)
while (inputStream.read(buffers).also { read = it } != -1) {
outputStream.write(buffers, 0, read)
}
inputStream.close()
outputStream.close()
return file.absolutePath
}
else
{
Log.d("","returnCursor is null")
return null
}
}
catch (e: Exception) {
Log.d("","exception caught at getFilePath(): $e")
return null
}
}
SimpleStorage didnt work on real device ( Samsung Galaxy Tab S7 FE Android 11 (R) ) but it was okay for emulator. Anyway i modified this code and its working perfectly now.
Its creating file in cache thats why its working perfectly with Android 11.
I am picking PDF via this function. Then i am passing the selected uri in onActivityResult or ActivityResultLauncher.
fun pickPDF(activityResult: ActivityResultLauncher<Intent>){
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "application/pdf"
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
activityResult.launch(intent)
}
pdfPickerResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult? ->
if (result != null) {
val intent = result.data
if (intent != null) {
val uri = intent.data
if (uri != null) {
requireContext().contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
val path = FileFinder.getFilePath(requireContext(),uri)
if (path != null && path.length > 3)
{
//Do your implementation.
}
else
{
Log.d("","PDF's path is null")
}
}
}
}
}
So ultimately we are getting Filepath from Uri on Android 11. If you want to do same thing for image etc you have to play with filePathColumn, intent values.
What about permissions ?
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
Add these flags in manifest file.
After that we need to ask permission in runtime.
fun checkAndRequestPermissions(context: Activity): Boolean {
val extStorePermission = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)
val cameraPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
val mediaLocationPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_MEDIA_LOCATION)
val listPermissionsNeeded: MutableList<String> = ArrayList()
if (cameraPermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CAMERA)
}
if (extStorePermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
if (extStorePermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
if (mediaLocationPermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.ACCESS_MEDIA_LOCATION)
}
if (extStorePermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.MANAGE_EXTERNAL_STORAGE)
}
if (listPermissionsNeeded.isNotEmpty()) {
ActivityCompat.requestPermissions(context, listPermissionsNeeded.toTypedArray(), REQUEST_ID_MULTIPLE_PERMISSIONS)
return false
}
return true
}
You can use this function. But we not done yet. We are still dont have full access.
We are going redirect user to app settings with that function.
private fun requestAllFilesAccessPermission(){
if (!Environment.isExternalStorageManager()) {
Snackbar.make(findViewById(android.R.id.content), "Permissin Needed", Snackbar.LENGTH_INDEFINITE)
.setAction("Settings") {
try {
val uri: Uri = Uri.parse("package:" + BuildConfig.APPLICATION_ID)
val intent =
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri)
startActivity(intent)
} catch (ex: Exception) {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivity(intent)
}
}.show()
}
}