From 0629deb4b5b6b03fd72965cf4e2fe2806d22044f Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 26 Feb 2022 17:55:30 +0000 Subject: [PATCH] Android: add java code to share files Android's sandbox makes us jump through hoops in order to share files with other apps. We need to declare a file provider and use specific paths where the files are located. Then we have java code (I couldn't make it work as JNI) that takes the filenames and creates content:// URIs for them and then hands those off to a sharing activity that is provided by Android. This can then be used to create attachments for support emails, or to share the log files with other apps - both of which will solve the annoying maximum log file length that we have with using the binder to add the log file text to the message body. This also finally replaces the 'compile' directive in build.gradle with 'implementation' - removing a warning that we've had for ages. Signed-off-by: Dirk Hohndel --- android-mobile/AndroidManifest.xml | 9 +++ android-mobile/build.gradle | 3 +- android-mobile/res/xml/filepaths.xml | 4 ++ .../mobile/SubsurfaceMobileActivity.java | 70 +++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 android-mobile/res/xml/filepaths.xml diff --git a/android-mobile/AndroidManifest.xml b/android-mobile/AndroidManifest.xml index 14e8ebf3a..36baecfca 100644 --- a/android-mobile/AndroidManifest.xml +++ b/android-mobile/AndroidManifest.xml @@ -77,6 +77,15 @@ + + + + + + diff --git a/android-mobile/src/org/subsurfacedivelog/mobile/SubsurfaceMobileActivity.java b/android-mobile/src/org/subsurfacedivelog/mobile/SubsurfaceMobileActivity.java index b9bc216d2..fc8ad27f6 100644 --- a/android-mobile/src/org/subsurfacedivelog/mobile/SubsurfaceMobileActivity.java +++ b/android-mobile/src/org/subsurfacedivelog/mobile/SubsurfaceMobileActivity.java @@ -20,10 +20,80 @@ import android.content.Intent; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.util.Log; +import java.io.File; +import android.net.Uri; +import android.support.v4.content.FileProvider; +import android.support.v4.app.ShareCompat; +import android.content.pm.PackageManager; +import java.util.List; +import android.content.pm.ResolveInfo; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; // this is the main class that will be run at start public class SubsurfaceMobileActivity extends QtActivity { + // FileProvider declares an 'authority' in AndroidManifest.xml + private static String fileProviderAuthority="org.subsurfacedivelog.mobile.fileprovider"; + + // you can share one file (for future use, I'm thinking divelist XML), or two files + // which is assumed to be a support request - maybe that shouldn't be implicit? + public boolean shareFiles(String path1, String path2) { + // better save than sorry + if (QtNative.activity() == null) + return false; + + Log.d(TAG + " shareFile - trying to share: ", path1 + " and " + path2); + + // Can't get this to work building my own intent, so let's use the IntentBuilder + Intent shareFileIntent = ShareCompat.IntentBuilder.from(QtNative.activity()).getIntent(); + shareFileIntent.setAction(Intent.ACTION_SEND_MULTIPLE); + + // now figure out the URI we need to share the first file + File fileToShare = new File(path1); + Uri uri; + try { + uri = FileProvider.getUriForFile(QtNative.activity(), fileProviderAuthority, fileToShare); + } catch (IllegalArgumentException e) { + Log.d(TAG + " shareFile - cannot get URI for ", path1); + return false; + } + Log.d(TAG + " shareFile - URI for file: ", uri.toString()); + + // because we allow up to two attachments, we use ACTION_SEND_MULTIPLE and so the attachments + // need to be an ArrayList - even if we only add one attachment this still works + ArrayList attachments = new ArrayList(); + attachments.add(uri); + + // if there is a second file name (that's for support emails) add it and set this up as support email as well + if (path2 != "") { + fileToShare = new File(path2); + try { + uri = FileProvider.getUriForFile(QtNative.activity(), fileProviderAuthority, fileToShare); + } catch (IllegalArgumentException e) { + Log.d(TAG + " shareFile - cannot get URI for ", path2); + return false; + } + Log.d(TAG + " shareFile - URI for file: ", uri.toString()); + attachments.add(uri); + // recipients are also always an array, even if there's only one + shareFileIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { "in-app-support@subsurface-divelog.org" }); + shareFileIntent.putExtra(Intent.EXTRA_SUBJECT, "Subsurface-mobile support request"); + shareFileIntent.putExtra(Intent.EXTRA_TEXT, "Please describe your issue here and keep the attached logs.\n\n\n\n"); + } + shareFileIntent.setType("text/plain"); + shareFileIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments); + shareFileIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + shareFileIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + Log.d(TAG + " sendFile ", " create activity for the Intent"); + // this actually allows sharing with any app that will take "text/plain" files, including Dropbox, etc + // in order for the recipient / subject to work, the user needs to be clever enough to share with an email app + QtNative.activity().startActivity(shareFileIntent); + return true; + } + + public static boolean isIntentPending; public static boolean isInitialized; private static final String TAG = "subsurfacedivelog.mobile";