I have a test program that requests access to the Android/obb folder, but I do not know how I can move files to this folder. I tried to use standard kotlin functions to manage files, but it didn't give any result. I also have a similar version written in Java.
private fun moveFile(src: File, dest: File): Boolean {
return src.renameTo(dest)
}
@RequiresApi(Build.VERSION_CODES.O)
private val handleIntentActivityResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode != Activity.RESULT_OK)
return@registerForActivityResult
val directoryUri = it.data?.data ?: return@registerForActivityResult
contentResolver.takePersistableUriPermission(
directoryUri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
if (checkIfGotAccess())
onGotAccess()
else
Log.d("AppLog", "you didn't grant permission to the correct folder")
}
@RequiresApi(Build.VERSION_CODES.Q)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val openDirectoryButton = findViewById<Button>(R.id.button1)
val test = findViewById<Button>(R.id.button2)
val test1 = findViewById<Button>(R.id.button3)
openDirectoryButton.setOnClickListener {
openDirectory()
}
test.setOnClickListener {
main()
}
test1.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
main1()
}
}
}
@RequiresApi(Build.VERSION_CODES.R)
private fun main1() {
val uri = Uri.parse("package:${BuildConfig.APPLICATION_ID}")
startActivity(
Intent(
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
uri
)
)
}
private fun main() {
val from = File(Environment.getExternalStorageDirectory(), "video.mp4")
val to = File(Environment.getExternalStorageDirectory(), "Android/obb/video.mp4")
try {
val isSuccess = moveFile(from, to)
if (isSuccess) {
val text = "File Moved Successfully!"
val duration = Toast.LENGTH_SHORT
val toast = Toast.makeText(applicationContext, text, duration)
toast.show()
} else {
val text = "File Moved Failed!"
val duration = Toast.LENGTH_SHORT
val toast = Toast.makeText(applicationContext, text, duration)
toast.show()
}
} catch (ex: IOException) {
ex.printStackTrace()
}
}
private fun checkIfGotAccess(): Boolean {
return contentResolver.persistedUriPermissions.indexOfFirst { uriPermission ->
uriPermission.uri.equals(androidTreeUri) && uriPermission.isReadPermission && uriPermission.isWritePermission
} >= 0
}
@RequiresApi(Build.VERSION_CODES.O)
private fun onGotAccess() {
Log.d("AppLog", "got access to Android folder. showing content of each folder:")
@Suppress("DEPRECATION")
File(Environment.getExternalStorageDirectory(), "Android/obb").listFiles()?.forEach { androidSubFolder ->
val docId = "$ANDROID_DOCID/${androidSubFolder.name}"
val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(androidTreeUri, docId)
val contentResolver = this.contentResolver
Log.d("AppLog", "content of:${androidSubFolder.absolutePath} :")
contentResolver.query(childrenUri, null, null, null)
?.use { cursor ->
val filesCount = cursor.count
Log.d("AppLog", "filesCount:$filesCount")
val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val mimeIndex = cursor.getColumnIndex("mime_type")
while (cursor.moveToNext()) {
val displayName = cursor.getString(nameIndex)
val mimeType = cursor.getString(mimeIndex)
Log.d("AppLog", " $displayName isFolder?${mimeType == DocumentsContract.Document.MIME_TYPE_DIR}")
}
}
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private fun openDirectory() {
if (checkIfGotAccess())
onGotAccess()
else {
val primaryStorageVolume = (getSystemService(STORAGE_SERVICE) as StorageManager).primaryStorageVolume
val intent =
primaryStorageVolume.createOpenDocumentTreeIntent().putExtra(EXTRA_INITIAL_URI, androidUri)
handleIntentActivityResult.launch(intent)
}
}
companion object {
private const val ANDROID_DOCID = "primary:Android/obb"
private const val EXTERNAL_STORAGE_PROVIDER_AUTHORITY = "com.android.externalstorage.documents"
private val androidUri = DocumentsContract.buildDocumentUri(
EXTERNAL_STORAGE_PROVIDER_AUTHORITY, ANDROID_DOCID
)
private val androidTreeUri = DocumentsContract.buildTreeDocumentUri(
EXTERNAL_STORAGE_PROVIDER_AUTHORITY, ANDROID_DOCID
)
}
I think I need to use SAF but haven't found the way I need in my situation.