1

I have some PDF files stored in /storage/emulated/0/Name123 directory like:

/storage/emulated/0/Name123/Key1/randomName1.pdf
/storage/emulated/0/Name123/Key2/randomName2.pdf
/storage/emulated/0/Name123/Key3/randomName3.pdf
and so on

Considering these files, my java android-studio-based application has a button that creates an ACTION_VIEW Intent. The idea is to allow users to open the PDF file with the PDF viewer/editor application of the user's choice. Everything works great except for one thing: all the changes and edits to the PDF file do not reflect on the actual file residing on the filesystem. So, if you click on the button, open the PDF and highlight some lines on a page, save it, and close the PDF reader application and get back to our application and click on the button to open the same file again, the same PDF without all those changes is going to be opened.

I have noticed a similar question without any answers on Stackoverflow.

By the way, I do not want to use solutions like the code below to avoid FileUriExposedException caused by supplying a file URI to an Intent on the new versions of Android:

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());

Is there any other way to launch another independent application to open a PDF file in a certain absolute path preserving the write access to the file?

Given the new restrictions for file URIs on new Android versions, how can the file manager apps launch third-party apps to open files, as I confirm that I can open a PDF file with X-plore, edit it, and save it back on the actual input file on the filesystem with the same PDF reader apps that fail to gain write access to my content URI, like Adobe Reader, Foxit Reader, XODO.

Here are my codes (Following this topic to use FileProvider):

File: Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    <application
        ...
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
    </application>
</manifest>

File: xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="."/>
</paths>

File: MainActivity.java Button's onClickListener

String key = "Key2/randomName2.pdf"
File path = new File("/storage/emulated/0/Name123");
File file = new File(path, key);

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = FileProvider.getUriForFile(getApplicationContext(),getApplicationContext().getPackageName()+".provider", file);
intent.setDataAndType(uri, "application/pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivity(intent, null);

// The application has the required permissions to access and manage ALL FILES on the external memory.
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
salehjg
  • 49
  • 1
  • 9
  • 1
    So the user chooses an app that writes edits to another file. Did you find out where? And which app was used? How many apps did you test? – blackapps Dec 23 '21 at 04:16
  • I tested it with adobe reader, foxit reader, and xodo on android R emulator and on a real Samsung S7 FE. The problem is apparent in all cases. So the actual file that gets sent to the pdf reader app seems to be a copy of the original file. I have noticed that launching and editing the same pdf file multiple times, saves multiple files with -.pdf, but I did not manage to find out where these files are actually created on the filesystem! @blackapps – salehjg Dec 23 '21 at 10:05
  • 1
    `So the actual file that gets sent to the pdf reader app seems to be a copy of the original file. ` No. It is the file itself that is sent to or read by the editor app. But after edit the editer app saves the content to another file. Do all these apps not have the possibility to save a file to a user determined location? Hard to believe. – blackapps Dec 23 '21 at 10:09
  • They all have save-as or save-a-copy functionality but that does not solve my problem. I want the user to have his/her own app of choice for viewing or editing the file. At the end, the file should have the edits withou my app's intervention. Also I tried `ACTION_EDIT` `Intent` and the results were the same. – salehjg Dec 23 '21 at 10:27
  • 1
    Yes i understand. But you can only blame those apps or better the programmers of them as there is no reason why edits could not be written to original file behind the uri. – blackapps Dec 23 '21 at 10:31
  • They work well with the file URIs and the changes are saved to the input file itself on the filesystem. The problem is there only for the content URIs by FileProvider. How can I find out where the saved copies of the edited PDFs are on the filesystem? Or can I send the PDFs to the third party apps and wait for the `intent`s results? – salehjg Dec 23 '21 at 10:38
  • 1
    Browse the file system to find out. Use file managers apps on your device or Device Explorer of Android Studio. – blackapps Dec 23 '21 at 10:42
  • I found out that the edited pdf files are stored at the local storage of Adobe Reader located at `/data/data/com.adobe.reader/files/Downloads/`. Also, I was thinking that how come on the same emulator, with the same Adobe Reader app, I can open the same input PDF file using a file manager like `X-plore` (or some other app) to edit the file and save it back on the filesystem automatically. How come just my app fails to achieve this? I guess the problem is in my code, otherwise, it shouldn't have been possible to save the file opened by any file managers, right? @blackapps – salehjg Dec 23 '21 at 16:23
  • No. It depends on file:// scheme or content:// scheme. And you have to use a content sheme by file provider. – blackapps Dec 23 '21 at 16:55
  • 1
    `/data/data/com.adobe.reader/files/Downloads/` That is an apps private directory and nobody hass acces. No filemagers also. – blackapps Dec 23 '21 at 16:56
  • I found an opensource kotlin based file manager that is using content URI and does not have the problem Im facing. I imported it in android studio and debugged it, it all comes down to this function to generate the correct URI: [Link to GitHub](https://github.com/SimpleMobileTools/Simple-Commons/blob/3d04cf87bd211758d9cdf9008b8bf019aa2865e1/commons/src/main/kotlin/com/simplemobiletools/commons/extensions/Context.kt#L325) – salehjg Dec 23 '21 at 19:30
  • I confirm that using this package `implementation 'com.github.SimpleMobileTools:Simple-Commons:d39bf6263d'`, It is possible to solve the problem with `openPathIntent(this, file.getPath(), false, BuildConfig.APPLICATION_ID, "", new HashMap<>(0));`. I have not yet studied the codes for this package, but it's working out of the box on Samsung S7 FE. A brief test on an emulator with API30 indicated that the same issue is still there, but as I mentioned, it works great on an actual device. The weird part is that u don't even need to have a provider in the app's manifest. – salehjg Dec 23 '21 at 20:58
  • 1
    With some strict mode tampering you can use a file uri instead of a content uri too i think. It will prevent the FileUriExposedException. Install an Intent Intercept app on your phone to see how the intent looks like. – blackapps Dec 23 '21 at 21:23
  • Found another question with my exact problem without any answer: https://stackoverflow.com/questions/68819154/how-to-open-pdf-on-android-using-intent-to-edit-file – salehjg Jan 01 '22 at 07:21

1 Answers1

0

You are asking to ACTION_VIEW the file, hence the app honoring your intent will consider it can only READ it.

The solution is to use Intent.ACTION_EDIT

Intent intent = new Intent(Intent.ACTION_EDIT);

More details in my answer here: Can not save PDF file with FileProvider and external PDF Editor

Pascal
  • 15,257
  • 2
  • 52
  • 65
  • I suspected this as well and tried it. It was *not* the problem. So far my observations indicate that: (1) the main problem is the PDF viewers like Adobe Reader, Foxit Reader, ... since they do not handle content URI's correctly. XODO for example has no such problem. (2) I guess file managers generate URI's similar to `com.github.SimpleMobileTools:Simple-Commons`. My experiments have shown this method has issues with recently created files. I do not remember what I did differently when I wrote the question, but XODO works fine. – salehjg Feb 13 '22 at 19:37