0

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)
}
MJegorovas
  • 750
  • 1
  • 6
  • 18
  • You should ask that the programmers of the word app i think. – blackapps Jan 29 '21 at 22:46
  • How exactly are you downloading the file? Dont you get an uri from the downloader? – blackapps Jan 29 '21 at 22:50
  • Install an intent intercept app on your phone and examine how your intent differs from the one of the file manager. – blackapps Jan 29 '21 at 22:53
  • Important is to know how the dowmloader saved the file to the Download directory. Which Android version on device? – blackapps Jan 29 '21 at 22:59
  • Hi blackapps, 1) just regular byte array written into file, yes I do get an uri which I then supply to external application for editing, but the problem is that editing app doesn't want to override the file contents of supplied uri 2) I'm testing on android 11 (30) at the moment, using MANAGE_EXTERNAL_STORAGE for testing. – MJegorovas Jan 30 '21 at 08:13
  • The problem isn't with how I download - for example I created word document through office app on public directory and when I try to send view intent from the other app to edit it in office the problem is still the same. – MJegorovas Jan 30 '21 at 08:49
  • `The problem isn't with how I download` No with how the downloader saved to file, created the file. Or how the office app creates a new file. As the file creater is the owner. And as the owner is important it is relevant how you downloaded. With DownloadManager or how? – blackapps Jan 30 '21 at 09:14
  • `yes I do get an uri which I then supply to external application for editing` No. You said you use a file provider. You get an uri from the file provider. Not from the downloader. – blackapps Jan 30 '21 at 09:17
  • Again download logic is not the problem here - I can download the file from my app to storage and if I open it from default file browser (eg. Google 'Files') word app can successfully override original file content. So I guess the problem is my FileProvider or teh Intent that I'm sending. But how do I debug what file browser does differently from my FileProvider? – MJegorovas Jan 30 '21 at 09:44
  • That i already told you. Did you install that app? – blackapps Jan 30 '21 at 09:51
  • `Again download logic is not the problem here` My god.. read my comments... Important is to know who downloaded , so to know who created the file in Download directory. To know which app is the owner. If you only would say that you are not using DownloadManager.. – blackapps Jan 30 '21 at 09:54
  • Okay, then to answer the download question - it's just custom download logic: get bytearray from server with ktor then write it to the file created with DocumentFile class. – MJegorovas Jan 30 '21 at 09:59
  • Aha.... With SAF ...... My god ... And you only tell that now... Well then you should use that saf uri of course. The uri you got at download. I said that before. Dont mess around with looking for a file path and a file provider. Use the saf uri. – blackapps Jan 30 '21 at 11:18
  • I did try that too, but the problem stays the same - word says that I have to create a copy if I want to persist changes. – MJegorovas Jan 30 '21 at 11:42
  • Please show full code where you start word. But start with onActivityResult where you obtain the saf uri. Tell which action you use to obtain the saf uri. – blackapps Jan 30 '21 at 11:48
  • Give me a minute, in the meantime I uploaded results from 'Intent-Interceptor' app if they can be of any use. I use `ACTION_OPEN_DOCUMENT_TREE`. – MJegorovas Jan 30 '21 at 11:54
  • Added code sample – MJegorovas Jan 30 '21 at 12:11
  • Doesn't write give both permissions? – MJegorovas Jan 30 '21 at 12:30
  • Do a test that instead of a action_view you use that saf uri to write to the file yourself or try to delete it. Do it at the same moment as when you would use that action. – blackapps Jan 30 '21 at 12:30
  • Yeah, I made a sample application in which I get the file uri from `ACTION_VIEW` and append to it. It succeeds (file size increases). – MJegorovas Jan 30 '21 at 12:40
  • That you could also have told before.. launchFlags=0x13000000; differs from launchFlags=0x3000000; You have an extra flag. You see that grand read/write flags are not mentioned as literals like the other ones. But they are in here. – blackapps Jan 30 '21 at 12:48
  • For the rest i am out of options and puzzled. Sorry. – blackapps Jan 30 '21 at 12:50
  • `FLAG_RECEIVER_FOREGROUND` (which is `Intent.FLAG_ACTIVITY_NEW_TASK`) is what makes the difference in launch flags, but even if I take it out it doesn't change the situation. – MJegorovas Jan 30 '21 at 12:52
  • Thank you for all your time. I guess the problem is with the word application implementation. – MJegorovas Jan 30 '21 at 13:01

1 Answers1

0

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!

Toukea Tatsi
  • 189
  • 1
  • 5