I'm currently making an app which download a file from a server and then open it.
I succeed to launch intent and open the file. However, I need sometimes to open this file in read-only mode, I did not succeed so far.
Here is my code :
var uri = FileProvider.getUriForFile(context!!, BuildConfig.APPLICATION_ID + ".fileprovider", lastSavedFile)
var openingDocumentIntent = Intent()
var fileMime = context!!.contentResolver.getType(uri)
openingDocumentIntent.action = Intent.ACTION_VIEW
openingDocumentIntent.setDataAndType(uri, fileMime)
openingDocumentIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context?.startActivity(openingDocumentIntent)
I have tried many ways :
FLAG_GRANT_WRITE_URI_PERMISSION
Intent.ACTION_VIEW and Intent.ACTION_EDIT
Moreover, I have seen many people complaining about Microsoft Apps such as Word which does not handle opening file in Write mode but only in Read-Only mode.
Does anyone knows how to open a file in read-only mode? (no matter which app opens it)
And the opposite... How to open a file in write mode with Microsoft App? (e.g Word)
Try to make your file read-only:
val f = File("path")
f.setReadOnly()
Related
I've seen the same question posted here: Android - how to only show(or able to select) files with a custom extension when calling "file selector" using Intent.ACTION_GET_CONTENT but they did not manage to solve it.
I want to force the user to pick a file with a custom extension .xyz from the file chooser. The intent is created something like this:
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = <what goes here?>
Is that possible to do?
If not, is there any alternative - like searching through the external storage to find all files with that file ending and return the data (collection of files) in the same manner an intent would do?
Use case: download file from my app open it with appropriate editing application and after user is done with editing upload the file back to my app.
Example: I download the docx file from my app to public folder (eg. 'Documents') and after getting uri with FileProvider I send ACTION_VIEW intent (giving write permissions). Then open it with word app and edit it. But then the problem arives - word app says I need to save the file as a new copy and doesn't let me override the original file. Strange thing is if I open that downloaded file from file browser everything works fine and I can override the file. But when I use Intent from my app word application decides to create a copy inside their private directory. Why are they doing it this way? Is there any possibility to either get the newly saved file back to my app (from startActivityForResult) or somehow make them override the original file in the public folder?
Edit: As blackapps sugested I tried to check intents with 'Intent-Interceptor'. Here are the results:
My application:
intent://com.android.externalstorage.documents/tree/primary%3ADocuments/document/primary%3ADocuments%2FDocument.docx#Intent;scheme=content;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document;launchFlags=0x13000000;end
------------
ACTION: android.intent.action.VIEW
DATA: content://com.android.externalstorage.documents/tree/primary%3ADocuments/document/primary%3ADocuments%2FDocument.docx
MIME: application/vnd.openxmlformats-officedocument.wordprocessingml.document
URI: intent://com.android.externalstorage.documents/tree/primary%3ADocuments/document/primary%3ADocuments%2FDocument.docx#Intent;scheme=content;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document;launchFlags=0x13000000;end
FLAGS:
FLAG_RECEIVER_FOREGROUND
FLAG_ACTIVITY_FORWARD_RESULT
FLAG_ACTIVITY_PREVIOUS_IS_TOP
------------
MATCHING ACTIVITIES:
Word (com.microsoft.office.word - com.microsoft.office.word.WordActivity)
Default file browser (Google 'Files'):
intent://com.google.android.apps.nbu.files.provider/1/file%3A%2F%2F%2Fstorage%2Femulated%2F0%2FDocuments%2FDocument.docx#Intent;scheme=content;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document;launchFlags=0x3000000;end
------------
ACTION: android.intent.action.VIEW
DATA: content://com.google.android.apps.nbu.files.provider/1/file%3A%2F%2F%2Fstorage%2Femulated%2F0%2FDocuments%2FDocument.docx
MIME: application/vnd.openxmlformats-officedocument.wordprocessingml.document
URI: intent://com.google.android.apps.nbu.files.provider/1/file%3A%2F%2F%2Fstorage%2Femulated%2F0%2FDocuments%2FDocument.docx#Intent;scheme=content;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document;launchFlags=0x3000000;end
FLAGS:
FLAG_ACTIVITY_FORWARD_RESULT
FLAG_ACTIVITY_PREVIOUS_IS_TOP
------------
MATCHING ACTIVITIES:
Word (com.microsoft.office.word - com.microsoft.office.word.WordActivity)
Here's how I obtain directory in which I save files (I use ActivityResultContracts):
directoryResultLauncher = registerForActivityResult(OpenDocumentTree()) { uri ->
if (uri == null) return#registerForActivityResult
requireContext().contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
authentication.publicDirectory = uri.toString()
}
Download method:
val directoryUriString = authentication.publicDirectory
val directory = DocumentFile.fromTreeUri(context, directoryUriString.toUri())
val file = directory!!.createFile(mimeType, title)
val fileResult = getFileContent(context.contentResolver.openOutputStream(file!!.uri)!!)
if (!fileResult.isError()) {
val intent = Intent(Intent.ACTION_VIEW, file.uri).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
startActivity(intent)
}
Below, I will try to suggest you possible causes and solutions for your encountered issue:
First, maybe the difference at the URI source level!
It looks like your app use a Uri like this one:
content://com.android.externalstorage.documents/tree/...
which is a TreeDocument uri from a DocumentFile
While the Explorer app uses a FileProvider Uri from a Io.File.
Second, maybe you have not submitted the grand_write_access flag
When you send the Uri to the word app, ensure you to add the flag:
Intent.FLAG_GRANT_WRITE_URI_PERMISSION that will allow the word app to get the write access on the resource.
Maybe the word app behaves differently depending on whether or not it has the write access permission on the submitted file.
Hope this enlightened you a bit!
I have a simple functionality in my application, user can download the file and then open it or share using any other installed application. Before android Q I hadn't any trouble with this, but with new privacy changes, I don't know how to do this correctly.
I need to do the next two steps:
Download file, using DownloadManager, in the common device Downloads folder (not in the application downloads folder)
Open this file or share this file (using intent)
To download the file to common Downloads folder I use next code
val request = DownloadManager.Request(config.uri)
.setTitle(title)
.setDescription(config.description)
.setNotificationVisibility(notificationVisibility)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "filename.pdf")
val downloadId = downloadManager.enqueue(request)
and after downloading done I getting downloaded file Uri like this
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor = downloadManager.query(query)
val fileUriStr = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
val fileUri = Uri.parse(fileUriStr)
In the end, when user click on button "Open", I creating next intent
val mime = context.contentResolver.getType(fileUri)
val intent = Intent()
.setAction(Intent.ACTION_VIEW)
.setDataAndType(uri, mime)
.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
All these solutions work properly until Android Q. On android Q after Intent start I see the dialog to chose target application, when I pick target application I get error that this application cant access the file (I use Adobe Reader as target application).
So, the question is how to do this operation correctly on Android 10?
P/S/ Sorry for my bad English
I had a same problem. I used DownloadManager.getUriForDownloadedFile() instead of the Uri returned from query and the problem solved! I don't know what exactly causes the problem but I found that this solution doesn't work on lower versions. So I ended up with this line:
var fileUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) downloadManager.getUriForDownloadedFile(requestId) else Uri.parse(fileUriStr)
Also I get the mime type from here:
val mime = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE))
And it works on all versions.
I'm trying to open a docx file in Word on Android using an Intent, but it always opens Read Only (Word prompts to say it is read only).
The file IS read-write in other apps that can edit a docx (e.g. WPS Office). Only Microsoft Word is the issue.
String fileUrl = "/storage/emulated/0/Download/test.docx";
File file = new File(fileUrl);
String mime = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
Uri theUri = FileProvider.getUriForFile(this,
"com.example.testint.fileprovider",
file);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
intent.setDataAndType(theUri, mime);
startActivity(intent);
I have run an Intent Intercept with several other apps. ASUS File Manager and ASTRO file manager and File Manager 1.36 are all able to open Word documents as Read/Write using content:// and do not have the read only issue. The intents look the same as my intent, so I cannot see how they can work, when this does not.
This is from ASUS file manager:
intent://com.asus.filemanager.OpenFileProvider/file/sdcard/Documents/Test.docx#Intent;scheme=content;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document;launchFlags=0x3000000;end
------------
ACTION: android.intent.action.VIEW
DATA: content://com.asus.filemanager.OpenFileProvider/file/sdcard/Documents/Test.docx
MIME: application/vnd.openxmlformats-officedocument.wordprocessingml.document
URI: intent://com.asus.filemanager.OpenFileProvider/file/sdcard/Documents/Test.docx#Intent;scheme=content;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document;launchFlags=0x3000000;end
FLAGS:
FLAG_ACTIVITY_FORWARD_RESULT
FLAG_ACTIVITY_PREVIOUS_IS_TOP
Has anyone else here managed to open Word documents for read AND write ok?
You can use the old file format e.g. file:///storage/emulated/0/Android/data/.../hello.docx or a content provider e.g. content://org.cryptomator.fileprovider/external_files/Android/data/org.cryptomator/cache/decrypted/hallo.docx BUT the file is not allowed to be in the app's internal storage. Then the files are writable!
Files with e.g. the .doc extension aren't writable or files located in internal storage aren't writable as well. Here you can find a short overview: https://github.com/cryptomator/cryptomator-android/issues/150#issuecomment-514401775
As android is increasing its security and changing some stuff now a days to make Android OS more secure to Vulnerabilities, its a good thing to understand new structure for developers to get into it.
I have been away from development from last couple of years.I just noticed that some stuff have been changed e.g file scheme of URI.
Case 1 : :
I am launching camera intent with custom URI mentioned below.
var takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(packageManager) != null) {
// Create the File where the photo should go
var photoFile: File? = null
try {
photoFile = createImageFile()
} catch (ex: IOException) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
val photoURI: Uri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".fileprovider",
photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO)
}
}
photoURI is custom URI.
When i took picture and check URI it has file:// in start from where i can get file path and i can do some stuff with it(i am uploading it to server)
Case 2
I am launching simple intent to pick image from gallery
val intent = Intent()
intent.type = "image/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(Intent.createChooser(intent, "Select Picture"), TYPE_IMAGE)
and now when i pick image and check URI its has content:// in start. And the trouble starts when i try to get file path from it. i have been searching into SOF but none of solutions worked for me.
My main purpose it get file path is that i want to pick file from device and upload it to server.But with content:// scheme i can not make a file from URI and thus can not send this file server.
i just read CommonsWareBlog about scheme system. it cleared few things but i still don't know how can i switch from content:// too file:// in my onActivityResult!
i would like to mention it again that current answers on SOF are not working for me that's why i have to ask this question in details.
I am using 7.0 device emulator
This is just an example of my problem in actual i am picking up PDF and DOCX files and want to upload them on server and after picking files i have URI with content:// scheme and i can not make a file and send to server.
i am not sure what i am missing about schemes.
I hope this question will help many other developers which are new to file system.
pleasure try to explain by code example according to my problem of picking file from intent (if you like)
Since Android 7.0, returning file:// scheme is discouraged (android changelog), since it can leak files from private folders. You can still encounter it, especially when using apps that target below Nougat.
Short answer is when you query for Intent.ACTION_GET_CONTENT You receive content:// uri that you can ContentResolver.openInputStream(Uri) on to obtain the data. This ensures item you picked is read-only, and masks it's real source - it might've been a file, provided remotely or generated by provider all together.