I have an Android application that basically stores a list of gpx files which are saved on the user's phone. When the user clicks on the filename in the application, it should prompt the user to open the gpx file with whatever routing applications are available on his phone. Right now I am testing with opening the file in Osmand. The problem is, Osmand is opening, but then immediately crashing.
The code that tries to open the file is this:
File gpxFile = new File(Path);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri gpxUri = FileProvider.getUriForFile(view.getContext(), AUTHORITY, gpxFile);
intent.setDataAndType(gpxUri, "application/gpx+xml");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
The gpx files all look like this:
<?xml version="1.0"?>
<gpx creator="{CREATOR}" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<wpt lat="{LAT_1}" lon="{LON_1}">
<name>{WPT_NAME_1}</name>
</wpt>
...
<wpt lat="{LAT_N}" lon="{LON_N}">
<name>{WPT_NAME_N}</name>
</wpt>
<trk>
<name>{TRACK_NAME}</name>
<trkseg>
<trkpt lat="{LAT_1}" lon="{LON_1}"></trkpt>
...
<trkpt lat="{LAT_N}" lon="{LON_N}"></trkpt>
</trkseg>
</trk>
</gpx>
At first I thought it was something wrong with the format of the gpx files, but if I open Osmand manually and try to import the file using "Configure map" -> "Gpx track", the track shows just fine on the map, including the waypoints.
LE: This is the error I get when Osmand tries to start:
08-16 17:28:00.524 5681-5762/? E/net.osmand: RenderingRuleProperty Rendering parse in strokeWidth_2
08-16 17:28:00.524 5681-5762/? E/net.osmand: RenderingRuleProperty Rendering parse in strokeWidth_2
08-16 17:28:01.259 5681-5681/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: net.osmand, PID: 5681
java.lang.RuntimeException: Unable to resume activity {net.osmand/net.osmand.plus.activities.MapActivity}: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{3ddadf4 5681:net.osmand/u0a203} (pid=5681, uid=10203) that is not exported from uid 10275
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3788)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2991)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{3ddadf4 5681:net.osmand/u0a203} (pid=5681, uid=10203) that is not exported from uid 10275
at android.os.Parcel.readException(Parcel.java:1693)
at android.os.Parcel.readException(Parcel.java:1646)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4861)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:5958)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2452)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1521)
at android.content.ContentResolver.query(ContentResolver.java:520)
at android.content.ContentResolver.query(ContentResolver.java:478)
at net.osmand.plus.helpers.GpxImportHelper.getNameFromContentUri(GpxImportHelper.java:108)
at net.osmand.plus.helpers.GpxImportHelper.handleContentImport(GpxImportHelper.java:69)
at net.osmand.plus.activities.MapActivity.onResume(MapActivity.java:617)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1277)
at android.app.Activity.performResume(Activity.java:7058)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3765)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2991)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Does Osmand lack the permission to read that file from the FileProvider? In other words, does it help to grant read permission in the intent before the call to startActivity:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
(I don't know if Osmand also needs write permissions. You could try adding that as well: FLAG_GRANT_WRITE_URI_PERMISSION).
I would also suggest carefully rechecking your FileProvider's configuration in filepaths.xml (in the 'xml' resource dir). Probably something like this:
<paths>
<files-path path="images/" name="myimages" />
</paths>
e.g. Is your file-paths attribute pointing to the right dir? Are the desired gpx files in that dir? (https://developer.android.com/training/secure-file-sharing/setup-sharing.html)
Another thing to keep in mind is that the authority string in the provider element must be unique on the device. So, in this part of your AndroidManifest, make sure you have replaced "com.example.myapp.fileprovider" with something unique to your app:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
If that doesn't help, I can only suggest watching the logcat output from the device to see if Osmand writes a stack trace for this crash.
--- EDIT 08/17/2017 ---
Just to put some details into the body of this answer: as A.M. proved and described in the comments below, the actual fix was to explicitly grant the necessary permissions to multiple, specific packages on the device by calling context.grantUriPermission repeatedly in a loop, something like this:
//grant permisions for all apps that can handle given intent
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
This approach is documented more here: https://stackoverflow.com/a/18332000/3482621
The need to call grantUriPermission (instead of just relying upon intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)) appears to depend on the Android platform version installed on the device. This is described in an issue report here: https://issuetracker.google.com/issues/37005552
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With