Reputation: 802
I am having trouble with an issue saving a PDF and CSV file to the Documents folder on Android. On two devices it seems to work (Samsung Galaxy Tab S8+ and Teclast M40 Plus), but on one device (Lenovo M10 Plus FHD 2nd Gen) it does not.
I tried various solutions and libraries and none seem to work. None of them seem to be able to get the file path from the URI.
This is my attempt usng the pickiT library;
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) {
Log.d("GraphActivity", "Result OK");
return;
}
Uri treeUri = data.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri docUri = DocumentsContract.buildDocumentUriUsingTree(treeUri,
DocumentsContract.getTreeDocumentId(treeUri));
String path = null;
int version = Build.VERSION.SDK_INT;
pickiT.getPath(docUri, version);
// Uri is from unknown provider
}
@Override
public void PickiTonCompleteListener(String path, boolean wasDriveFile, boolean wasUnknownProvider, boolean wasSuccessful, String Reason) {
Log.d("GraphActivity", "Path is not null");
folder = new File(path);
String timestamp = new SimpleDateFormat("MM_dd_yy_hh.mm", Locale.getDefault()).format(new Date());
baseFilename = name + " " + timestamp;
filename = "/" + folder.toString() + "/" + baseFilename + ".csv";
if (filename == null) {
Log.d("GraphAcitivty", "Filename is null");
} else {
Log.d("GraphAcitivty", "Filename is not null");
}
showSaveDialog();
}
Apparently PickiTonCompleteListener
isn't even being called based on my print statements. My activity does implement PickiTCallbacks
but for some reason the callback isn't working.
I wonder, is there any solution out there that works?
Upvotes: 0
Views: 645
Reputation: 802
I figured it out.
Instead of using the File
class I can use DocumentFile
and do this:
final DocumentFile csvFile = pickedDir.createFile("text/csv", baseFileName);
if (csvFile != null) {
out = context.getContentResolver().openOutputStream(csvFile.getUri());
}
Did not have to use the PickiT library to do this. For the PDF file, I use MIME type application/pdf
.
Upvotes: 0
Reputation: 438
when u want to insert a new document, the preferred way is to Use DownloadsFolder, on api Q+(api 29)
there's a content provider that makes it easy .
this code will be compatible with all android version.
Hint below android 10 u can use Document Folder for this solution but the recommended is to use
Downloads Folder
.
this is kotlin code convert it to java
if this helped pls upvote
fun example() {
var filename = "yourFileName_${System.currentTimeMillis()}.pdf"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val uri = MediaStoreUtils.createDownloadUri(context, filename)
if(uri == null){
return
}
try {
context.contentResolver.openOutputStream(uri, "w")?.use { outputStream ->
//write your file InputStream to the OutputStream
}
} catch (e: IOException) {
Log.e(TAG, e.printStackTrace().toString())
}
} else {
val downloadsFolder =
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)
//re-generate the filename until we can confirm its uniqueness
while (File(downloadsFolder, filename).exists()) {
filename = generateFilename(type.extension)
}
val file = File(downloadsFolder, filename)
try {
file.outputStream().use { outputStream ->
//write your file InputStream to the OutputStream
}
} catch (e: IOException) {
Log.e(TAG, e.printStackTrace().toString())
}
}
}
@RequiresApi(Build.VERSION_CODES.Q)
fun createDownloadUri(context: Context, filename: String): Uri? {
val downloadsCollection =
MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val newFileValues = ContentValues().apply {
put(MediaStore.Downloads.DISPLAY_NAME, filename)
}
// is better to execute off the main thread
// run on Background Thread (IO)
return context.contentResolver.insert(downloadsCollection, newFileValues)
}
Upvotes: 1