I have targeted Android API level 30 and tried to create multiple file descriptors for a single file from the URI from the default file picker which looks like this.
content://com.android.externalstorage.documents/document/E8A6-89C4%3AMovies%2FTestFile.mp4
content://com.android.externalstorage.documents/document/primary%3ATestFile.mp4
I am using the below code to create 10 threads to asynchronously access a file with ParcelFileDescriptors.
public class TestActivity extends AppCompatActivity {
public static final String TAG = "TEST_LOG";
private Button pickFileBtn;
final int VIDEO_REQUEST_CODE = 111;
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.test_activity);
pickFileBtn = findViewById(R.id.pick_file);
pickFileBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pickFile();
}
});
}
private void pickFile() {
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, VIDEO_REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == VIDEO_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
loadFrame(data.getData());
}
}
}
void loadFrame(Uri uri) {
for (int i = 0; i < 10; i++) {
new Thread(new CustomRunnable(uri)).start();
}
}
}
class CustomRunnable implements Runnable {
private Uri uri;
public CustomRunnable(Uri uri) {
this.uri = uri;
}
@Override
public void run() {
try {
ParcelFileDescriptor descriptor = null;
try {
descriptor = CustomApplication.appContext.getContentResolver().openFileDescriptor(uri, "r");
// Working with the descriptor here.
} catch (Exception e) {
Log.e(TestActivity.TAG, String.format("Failed to obtain parcelFileDescriptor for %s.%s", uri.toString(), e.getMessage()));
} finally {
if (descriptor != null)
descriptor.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Failed to obtain r parcelFileDescriptor for content://com.android.externalstorage.documents/document/primary%3ATestFile.mp4.Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/document/primary%3ATestFile.mp4 from pid=6190, uid=12283 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
This can create around 5 descriptors and throws File Not Found Exception for the rest. But, It can successfully create all the required descriptors when I use URI from the media store
. And the media store URI looks like this.
content://media/external/video/media/268019
I have tried to reuse the 5 descriptors but when I try to read the files using them, I get an error saying EBML header parsing failed
I have also tried to obtain access to a specific folder using Intent.ACTION_OPEN_DOCUMENT_TREE
and then picking a file, but the result is the same, that it only opens 5 descriptors.
Why do opening descriptors from the default file picker only create 5 descriptors and why I can not reuse them.