File written using ACTION_CREATE_DOCUMENT is empty on Google Drive but not local storage
The comment from @greenapps put me on the right path. Changing it to use getContentResolver().openOutputStream(...)
fixed the problem:
try {
OutputStream os = c.getContentResolver().openOutputStream(uri);
if( os != null ) {
os.write(data.getBytes());
os.close();
}
}
catch(IOException e) {
e.printStackTrace();
}
Update: After awhile of using this in my app, the problem re-occurred (files written to Google Drive were 0 bytes, but could be written locally). Clearing the cache data for my app solved it again.
Refer to official documentation at https://developer.android.com/guide/topics/providers/document-provider
On Android 4.3 and lower, if you want your app to retrieve a file from another app, it must invoke an intent such as ACTION_PICK or ACTION_GET_CONTENT. The user must then select a single app from which to pick a file and the selected app must provide a user interface for the user to browse and pick from the available files.
On Android 4.4 (API level 19) and higher, you have the additional option of using the ACTION_OPEN_DOCUMENT intent, which displays a system-controlled picker UI controlled that allows the user to browse all files that other apps have made available. From this single UI, the user can pick a file from any of the supported apps.
On Android 5.0 (API level 21) and higher, you can also use the ACTION_OPEN_DOCUMENT_TREE intent, which allows the user to choose a directory for a client app to access.
For me the following solution works perfect for both local as well as google drive on Android 9
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && data != null) {
if (requestCode == REQUEST_SAVE_File) {
try {
stream = getContentResolver().openOutputStream(data.getData());
((BitmapDrawable) imageView.getDrawable()).getBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
strem.close(); ///very important
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
And intent is created as follows
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/png");
intent.putExtra(Intent.EXTRA_TITLE, "my-image.png");
startActivityForResult(intent, REQUEST_SAVE_FILE);
Make sure you close the stream after writing. Otherwise file may not be saved.