Search code examples
androidandroid-intentandroid-contentprovider

NullPointerException in other app while sharing a file on internal storage


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!


Solution

  • 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.