This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Download a file from Android share intent

My app has the option to share a generated GPX file (a hiking route) with other applications. I'm using the ACTION_SEND intent for this. It works well, and users can share the GPX files with other apps and with other people via email etc.

However, some apps do not seem to accept receiving this data via intents. Garmin Connect does not show up in the list of apps when I'm sharing a GPX file, using the content type "application/gpx+xml".

If I download the GPX file manually and then open it, then Garmin Connect is listed as an app that can open it.

Is there any way to add a "Download file" to the share chooser intent that pops up when sharing a file?

Here is the client code I'm using:

private final WeakReference<MainActivity> mainActivityWeakReference;

public FileExportTask(MainActivity mainActivity) {
    this.mainActivityWeakReference = new WeakReference<>(mainActivity);
}

@Override
public void run() {
    MainActivity mainActivity = mainActivityWeakReference.get();

    if (mainActivity == null) {
        // TODO: handle that mainActivity doesn't exist
        return;
    }

    try {
        Uri uri = getUriForSelectedRoute();
        mainActivity.runOnUiThread(() -> {
            Intent shareIntent = new Intent();
            shareIntent.setAction(Intent.ACTION_SEND);
            shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
            shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            shareIntent.setType("application/gpx+xml");
            Intent chooser = Intent.createChooser(shareIntent, mainActivity.getString(R.string.share_route));

            List<ResolveInfo> resInfoList = mainActivity.getPackageManager().queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY);
            for (ResolveInfo resolveInfo : resInfoList) {
                String packageName = resolveInfo.activityInfo.packageName;
                mainActivity.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }

            mainActivity.startActivity(chooser);
        });
    } catch (Exception ioe) {
        mainActivity.runOnUiThread(() -> Toast.makeText(mainActivity, R.string.failed_route_share, Toast.LENGTH_SHORT).show());
    }
}

private Uri getUriForSelectedRoute() throws Exception {

    Route selectedRoute = RouteResponseProvider.getInstance().getSelectedRoute();
    return downloadRoute(selectedRoute.toGpxUrl());
}

private Uri downloadRoute(String url) throws IOException {

    String filename = "route_"+System.currentTimeMillis()+".gpx";
    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(new UserAgentInterceptor())
            .build();

    Request httpRequest = new Request.Builder()
            .url(url)
            .build();

    try (Response response = client.newCall(httpRequest).execute()) {
        File downloadedFile = new File(getFilesDirectory(), filename);
        BufferedSink sink = Okio.buffer(Okio.sink(downloadedFile));
        sink.writeAll(response.body().source());
        sink.close();
        return getContentUri(downloadedFile);
    }
}

private File getFilesDirectory() {
    MainActivity mainActivity = mainActivityWeakReference.get();
    File dir = mainActivity.getFilesDir();
    if (dir != null && !dir.exists()) {
        dir.mkdirs();
    }
    return dir;
}

private Uri getContentUri(File file) {
    MainActivity mainActivity = mainActivityWeakReference.get();
    return FileProvider.getUriForFile(mainActivity, "com.myapp.fileprovider", file);
}

And this is in my AndroidManifest.xml:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.myapp.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

  • I was searching for a solution on the same issue but as an end user, not as developer. My conclusion is that Garmin connect simply doesn't support that (for whatever reason). As a workaround, you could try to use the "open" instead of "share" in your app. You can check the app WRPElevationChart, which is doing exactly that. 

  • This is how the mentioned WRPElevationApp is handling this task:

    Some Ccde fragments, that should hopefully help :-)

    -------

    // create a Fileprovider based URI
    Uri uri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", file);

    // Do the export stuff (e.g create GPX file)
    ExportGPXTask(uri, true, SharedData.GPX);

    ...
    final Uri[] iuri = new Uri[1];
    ...
    iuri[0] = uri;

    // after ExportGPXTask is performed share the GPX file (like an onPostExecute() event)
    if (doshare && iuri[0] != null) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    getApplicationContext().grantUriPermission(getApplicationContext().getPackageName(), iuri[0], Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

    switch (exttype) {
    case SharedData.GPX:
    intent.setDataAndType(iuri[0], "application/gpx+xml");
    break;
    }


    startActivity(intent);
    }

    ------

    Good luck!