0

I need to send binary content from my app to whatever app opens that file type in the device.

I'm following these instructions: https://developer.android.com/training/sharing/send.html#send-binary-content

Here's my code:

final FileType fileType
final File file;

final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(AncestryApplication.getAppContext(), AncestryApplication.getAppContext().getApplicationContext().getPackageName() + ".provider", file));

intent.setType(fileType.getMimeType());
startActivity(intent);

A few things:

  1. If I change the intent action from ACTION_VIEW to ACTION_SEND, I get the wrong possible list of apps to open my file
  2. ACTION_SEND seems to work, but only with small file sizes
  3. intent.setDataAndType() seems to work fine on devices OS M and lower. On N I get the same TransactionTooLargeException

At the end, this is what I need to accomplish:

  • I already have a file saved, and it is stored at file:///storage/emulated/0/Download/TempFile.html
  • Since the file may be too large, I need to send just the location of the file to a third party app (like adobe pdf reader) to open the file
  • No issues on M or lower, tons of issues on N

Any ideas on what I may be doing wrong? I've been trying to solve this for a few days and I've read a ton of tutorials and SO suggestions, without any final answer.

Thanks.

EDIT: here's my stacktrace:

AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.android.apps.myapp, PID: 26785
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 27943540 bytes
  at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3752)
  at android.os.Handler.handleCallback(Handler.java:751)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:154)
  at android.app.ActivityThread.main(ActivityThread.java:6077)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

Caused by: android.os.TransactionTooLargeException: data parcel size 27943540 bytes
  at android.os.BinderProxy.transactNative(Native Method)
  at android.os.BinderProxy.transact(Binder.java:615)
  at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3606)
  at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3744)
  at android.os.Handler.handleCallback(Handler.java:751) 
  at android.os.Handler.dispatchMessage(Handler.java:95) 
  at android.os.Looper.loop(Looper.java:154) 
  at android.app.ActivityThread.main(ActivityThread.java:6077) 
  at java.lang.reflect.Method.invoke(Native Method) 
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

EDIT 2: Added onSaveInstanceState() code from base fragment:

@Override
public void onSaveInstanceState(final Bundle outState) {
    mSaveInstanceStateCalled = true;
    outState.putBoolean(KEY_PROCESSING_SAVE, mSaveInProgress);
}
Gimby
  • 5,095
  • 2
  • 35
  • 47
TooManyEduardos
  • 4,206
  • 7
  • 35
  • 66
  • Your `Intent` should not be anywhere near the 1MB IPC transaction limit, as the actual size of the stream doesn't count. Could you edit your question and post your entire Java stack trace? For example, with similar code, I just launched `ACTION_VIEW` for a ~6MB MP4 file on a Nexus 9 running Android 7.0, with no issues. – CommonsWare Sep 07 '16 at 22:34
  • done. thanks for your help, again – TooManyEduardos Sep 07 '16 at 22:38
  • `ACTION_VIEW` does not use `EXTRA_STREAM`. `ACTION_VIEW` would use `setDataAndType()`. `ACTION_SEND` uses `EXTRA_STREAM`. None of that explains your stack trace, but your code should not even be getting that far. What sort of file is this, and what is the app that you are using to try to view it? – CommonsWare Sep 07 '16 at 22:43
  • I can change the code to whatever you suggest, so just let me know if you want to try something up. The files are mainly pdf, doc, docx, or html. – TooManyEduardos Sep 07 '16 at 22:45
  • If you want to use `ACTION_VIEW`, remove the `EXTRA_STREAM` line, and convert your `setType()` to `setDataAndType()`, providing your `Uri` there. I just want to confirm that you are getting this crash with that combination. – CommonsWare Sep 07 '16 at 22:48
  • I do, I get the exact same crash. This way (the one you just suggested) is how we originally had it, and how it works for OS < N – TooManyEduardos Sep 07 '16 at 22:49
  • :: shrug :: I just used `FileProvider` to serve a 65.7MB PDF file on that Nexus 9, from the `Download/` directory on external storage, without issue. Make sure that you are on the latest support libraries (24.2.0 at present) and that you hold an external storage permission (including runtime permission logic if your `targetSdkVersion` is 23 or higher, which I assume that it is). – CommonsWare Sep 07 '16 at 22:56
  • It looks like the exception is thrown when the Activity is stopped. So the reason might be the Bundle saved in `onSaveInstanceState()` rather than the Intent you're trying to start. – cketti Sep 08 '16 at 00:11
  • @CommonsWare I'm still going down this rabbit hole. I am using support library 24.2.0, external permission is enabled (including the runtime version of it), and my `targetSdkVersion` is 24. I don't get this issue with 23. The crash seems to be trigged by the base activity on `onSaveInstanceState` – TooManyEduardos Sep 12 '16 at 02:04
  • 3
    At this point, all that I can recommend is that you try to create a separate standalone project that reproduces the issue. It is possible that, as part of building that sample project, you will determine what the actual cause is in your main project. This is particularly true if you have difficulty reproducing the issue, as it will force you to incrementally incorporate more of your main app's code in the sample. If you can create a sample that reproduces the problem and you did not uncover the cause, upload that sample somewhere and link to it from here. – CommonsWare Sep 12 '16 at 11:12
  • I guess the part I'm trying to understand is why this causes a crash now. If the targetSdkVersion is 23, I still get the `TransactionTooLargeException` message in the logs, but the app doesn't crash. If the targetSdkVersion is 24, this message crashes the app. – TooManyEduardos Sep 12 '16 at 15:12
  • Possible duplicate of [What to do on TransactionTooLargeException](http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception) – Cypher Sep 14 '16 at 18:45
  • 2
    `data parcel size 27943540` Send in smaller chunks. https://developer.android.com/reference/android/os/TransactionTooLargeException.html – Cypher Sep 14 '16 at 18:50
  • Possible duplicate of [Why does Android N throw TransactionTooLargeException when using Bundles?](http://stackoverflow.com/questions/39507250/why-does-android-n-throw-transactiontoolargeexception-when-using-bundles) – Tim Sep 15 '16 at 09:43
  • Tim, that question is marked as possible duplicate of my question (this question) – TooManyEduardos Sep 15 '16 at 14:52
  • @TooManyEduardos that question is not marked dups , just suggested by someone and that suggestion is wrong , this should be considered dup of that question – JAAD Sep 19 '16 at 07:41

1 Answers1

7

The exception in the logcat you posted is caused by packing too much data into the Bundle processed by onSaveInstanceState.

Here is the method from the Android source where it is thrown, if the build version is N or greater:

private static class StopInfo implements Runnable {
    ActivityClientRecord activity;
    Bundle state;
    PersistableBundle persistentState;
    CharSequence description;
    @Override public void run() {
        // Tell activity manager we have been stopped.
        try {
            if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
            ActivityManagerNative.getDefault().activityStopped(
                activity.token, state, persistentState, description);
        } catch (RemoteException ex) {
            if (ex instanceof TransactionTooLargeException
                    && activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
                Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
                return;
            }
            throw ex.rethrowFromSystemServer(); // <<-- exception thrown here
        }
    }
}

I am posting this in the form of an answer because it's too long for a comment. It is not meant as a complete answer to the question, because there is not enough information in the question to answer it.

x-code
  • 2,940
  • 1
  • 18
  • 19
  • I've placed breakpoints to this class, but nothing gets called here. It is possible though because the crash happens after the "onSaveInstanceState" of the base fragment class – TooManyEduardos Sep 08 '16 at 15:57
  • What do the `onSaveInstanceState` methods of your fragment(s) and activities put into the bundle? Post that code. – x-code Sep 08 '16 at 17:18
  • Done. The subclass does not implement `onSaveInstanceState` – TooManyEduardos Sep 08 '16 at 18:38
  • Answer updated. – x-code Sep 08 '16 at 20:13
  • Sorry about the delay, I've been sick all day. What's the updated answer? I also dont get a break point to stop on anything inside the Stop method, so that makes this harder. Webviews can be used, specially for html files, but this is up to the user. We also allow Chrome, or another browser to open the same file. For pdf and doc/docx files, we don't use webviews. Thank you for your help – TooManyEduardos Sep 09 '16 at 03:38
  • Looking at the way you use built-in classes that might have a lot of instance state is the only new suggestion I have. Only you know your code. – x-code Sep 10 '16 at 02:30
  • I downvoted your answer, because it doesn't really give a solution. If you need more information in order to provide a solution, then first ask in comments. – dragi Sep 14 '16 at 14:28