0

In our app, we found it necessary to open documents from our internal storage through an intent to another app. i.e. open a pdf we have stored internally in the user's default pdf reader of choice.

In the manifest, I've set the app to be a provider and in our Provider class, I've implemented the openFile(Uri uri, String mode) method which gets called, and does not throw a FileNotFoundException.

I've verified that the file is present in the expected location - and that the intent is not null, and in fact looks correct.

However, when I send a new Intent, the app trying to open the file dies with a NPE. For example, this is the stack trace when trying to open a PDF:

02-26 14:53:59.047: E/AndroidRuntime(4138): FATAL EXCEPTION: main
02-26 14:53:59.047: E/AndroidRuntime(4138): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tf.thinkdroid.sg/com.tf.thinkdroid.pdf.app.RenderScreen}: java.lang.NullPointerException
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.ActivityThread.access$600(ActivityThread.java:130)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.os.Looper.loop(Looper.java:137)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.ActivityThread.main(ActivityThread.java:4745)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at java.lang.reflect.Method.invokeNative(Native Method)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at java.lang.reflect.Method.invoke(Method.java:511)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at dalvik.system.NativeStart.main(Native Method)
02-26 14:53:59.047: E/AndroidRuntime(4138): Caused by: java.lang.NullPointerException
02-26 14:53:59.047: E/AndroidRuntime(4138):     at com.tf.thinkdroid.pdf.app.RenderScreen.onNewIntent(Unknown Source)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at com.tf.thinkdroid.pdf.app.RenderScreen.onCreate(Unknown Source)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.Activity.performCreate(Activity.java:5008)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
02-26 14:53:59.047: E/AndroidRuntime(4138):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
02-26 14:53:59.047: E/AndroidRuntime(4138):     ... 11 more
02-26 14:53:59.054: W/ActivityManager(251):   Force finishing activity com.tf.thinkdroid.sg/com.tf.thinkdroid.pdf.app.RenderScreen

I can't think of any way of debugging this since it's happening outside my app, and I'm just not sure why it's happening. Does any one have some insight into what might cause this or how I can fix it?

Thanks!

EDIT: This is how I am creating the Intent.

  Intent intent = new Intent(Intent.ACTION_VIEW);
  String extension = EventUtil.getExtension(file);
  String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
  Uri uri = Uri.parse(getContext().getPackageName() + file.getPath());
  intent.setDataAndType(uri, type);

And launching intent with:

getContext().startActivity(intent);

Another Edit!

After fixing the mangled url (see comment below) my ContentProvider openFile() is being called, and not throwing any exceptions, but the receiving app still crashes.

And yet another edit.....

This is certainly a problem with how I'm handling the Uri - the code in the SO answer I linked to in comments below seems to give me some extra path information that I don't want (i.e. data/data/com.xxxxx.xxxxx/files/files/subdir/filename - too many files directories!) But I have yet to figure out how to get exactly what I need to create the url properly!

  • 1
    Post the code you use to create the Intent and a sample Intent that causes the crash. – David Wasser Feb 26 '14 at 23:10
  • is `getContext().getPackageName() + file.getPath()` the correct way to obtain the uri for the file? – njzk2 Feb 26 '14 at 23:32
  • njzk2, I was typing out that it was, and showing a sample of what I got from it, but noticed some extra path information! that might be what the problem is. Going to test it now... (Proof that coding when exhausted isn't the best idea??? Maybe...) – alphanumeric character Feb 26 '14 at 23:35
  • Well, that certainly wasn't HELPING matters any, but it was a red herring... I've fixed the Uri, and it's still crashing :( Incidentally, I was using this as a basis for creating this functionality: http://stackoverflow.com/questions/21304489/how-to-open-private-files-saved-to-the-internal-storage-using-intent-action-view/21305564#21305564 – alphanumeric character Feb 26 '14 at 23:43

1 Answers1

0

So, it turns out that this is entirely a Uri issue. Passing a Uri with the wrong scheme (i.e. file:/// ) causes the receiving app to crash, because it can't resolve the Uri to a file properly - it NEEDS to be a content:// Uri scheme. Sadly, I didn't find any way of resolving that type of scheme without adding frameworks to our app, (Android support 4 apparently has a FileProvider class that does exactly this.) so I had to make a String constant to hold the first part of the Uri, and then just tack on the correct path at the end.

I've seen several answers saying that you can call getContext().getPackageName() + file.getPath() but as user njkz2 pointed out, that is not right. Without the correct framework, you need to either write your own class to handle Uri's to pass back the correct scheme, or you need to make a String constant to point to your own internal files directory.