Compare commits

...

5 Commits

Author SHA1 Message Date
Dirk Hohndel
c4660ffe29 build-system: don't fail with multi-part path
If the CMAKE_PREFIX_PATH is a multi element path the old code failed
in very predictable ways. So instead simply fall back on the PATH to
find qmake.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-02-27 14:14:14 -08:00
Dirk Hohndel
354fb15776 mobile/profile: fix scaling of profile for HDPI screens
For reasons I don't understand, the device pixel ratio was taken into account
twice. And as a result the transformation applied to the profile made us show
only the top left part of it - but enlarged (depending on the DPR).

This code fixes that problem by simply forcing the transformation used by the
painter to be the identity matrix. I worry that this could be wrong in some
situations, but for now it seems to fix the problem.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-02-27 13:20:20 -08:00
Dirk Hohndel
95e2ded5a4 Android: use shareFile for support email
This way we can have attachment of fairly arbitrary size (which should
be extremely useful for long libdivecomputer logs). This isn't quite as
intuitive as what we did before - the user needs to pick an email app to
share with), but that doesn't seem too bad - and also... this way they
can share logfiles via Dropbox or analyze them in other apps).

If the file share fails for some reason, we fall back to the old method
with passing the combined logs as body to the support message.

As an implementation detail this keeps the correct path for the app log file around
(this was stupidly overwritten before).

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-02-26 18:39:36 +00:00
Dirk Hohndel
ad0e346714 Android: use a sharable location for our files
The first location we should try is one that allows us to share files.
In theory this should work on every device, but we do have a few
fall-backs, just in case.

This also moves the Android specific include to the top which seems much
more standard.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-02-26 18:19:37 +00:00
Dirk Hohndel
0629deb4b5 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 <dirk@hohndel.org>
2022-02-26 18:09:51 +00:00
9 changed files with 119 additions and 9 deletions

View File

@ -1,3 +1,5 @@
- mobile: fix profile scaling issue on high DPR devices
- mobile/Android: add logfiles as attachment to support emails
- planner: make ESC (cancel plan) work when moving handles
- dive list: make dive guide visible in dive list [#3382]
- general: rename dive master to dive guide

View File

@ -77,6 +77,15 @@
<meta-data android:name="android.max_aspect" android:value="3" />
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="org.subsurfacedivelog.mobile.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
<uses-sdk android:minSdkVersion="21"

View File

@ -27,8 +27,9 @@ allprojects {
apply plugin: 'com.android.application'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.github.mik3y:usb-serial-for-android:v3.4.3'
implementation 'com.android.support:support-v4:25.3.1'
}
android {

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path path="./" name="logfiles" />
</paths>

View File

@ -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<Uri> attachments = new ArrayList<Uri>();
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";

View File

@ -48,7 +48,8 @@ bool subsurface_ignore_font(const char *font)
static const char *system_default_path_append(const char *append)
{
// Qt appears to find a working path for us - let's just go with that
QString path = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first();
// AppDataLocation allows potential sharing of the files we put there
QString path = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).first();
if (append)
path += QString("/%1").arg(append);

View File

@ -55,6 +55,7 @@
#include "commands/command.h"
#if defined(Q_OS_ANDROID)
#include <QtAndroid>
#include "core/serial_usb_android.h"
std::vector<android_usb_serial_device_descriptor> androidSerialDevices;
@ -230,9 +231,11 @@ QMLManager::QMLManager() :
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#if defined(Q_OS_ANDROID)
// on Android we first try the GenericDataLocation (typically /storage/emulated/0) and if that fails
// (as happened e.g. on a Sony Xperia phone) we try several other default locations, with the TempLocation as last resort
// on Android we first try the AppDataLocation (which allows sharing of files), then the
// GenericDataLocation (typically /storage/emulated/0), and if that fails (as happened e.g. on a
// Sony Xperia phone) we try several other default locations, with the TempLocation as last resort
QStringList fileLocations =
QStandardPaths::standardLocations(QStandardPaths::AppDataLocation) +
QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation) +
QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation) +
QStandardPaths::standardLocations(QStandardPaths::DownloadLocation) +
@ -260,7 +263,8 @@ QMLManager::QMLManager() :
appendTextToLog("Successfully opened logfile " + appLogFileName
+ " at " + QDateTime::currentDateTime().toString());
// if we were able to write the overall logfile, also write the libdivecomputer logfile
QString libdcLogFileName = appLogFileName.replace("/subsurface.log", "/libdivecomputer.log");
QString libdcLogFileName = appLogFileName;
libdcLogFileName = libdcLogFileName.replace("/subsurface.log", "/libdivecomputer.log");
// remove the existing libdivecomputer logfile so we don't copy an old one by mistake
QFile libdcLog(libdcLogFileName);
libdcLog.remove();
@ -488,8 +492,25 @@ void QMLManager::copyAppLogToClipboard()
bool QMLManager::createSupportEmail()
{
QString messageBody = "Please describe your issue here and keep the logs below:\n\n\n\n";
#if defined(Q_OS_ANDROID)
// let's use our nifty Java shareFile function
QAndroidJniObject activity = QtAndroid::androidActivity();
if (activity.isValid()) {
QAndroidJniObject applogfilepath = QAndroidJniObject::fromString(appLogFileName);
QAndroidJniObject libdcfilepath = QAndroidJniObject::fromString(logfile_name);
bool success = activity.callMethod<jboolean>("shareFiles",
"(Ljava/lang/String;Ljava/lang/String;)Z", // two string arguments, return bool
applogfilepath.object<jstring>(), libdcfilepath.object<jstring>());
qDebug() << __FUNCTION__ << "shareFiles" << (success ? "succeeded" : "failed");
if (success)
return true;
}
qDebug() << __FUNCTION__ << "failed to share the logFiles via intent, use the fall-back mail body method";
#endif
QString mailToLink = "mailto:in-app-support@subsurface-divelog.org?subject=Subsurface-mobile support request";
mailToLink += "&body=Please describe your issue here and keep the logs below:\n\n\n\n";
mailToLink += "&body=";
mailToLink += messageBody;
mailToLink += getCombinedLogs();
if (QDesktopServices::openUrl(QUrl(mailToLink))) {
appendTextToLog("OS accepted support email");
@ -1826,8 +1847,6 @@ void QMLManager::writeToAppLogFile(QString logText)
//HACK to color the system bar on Android, use qtandroidextras and call the appropriate Java methods
//this code is based on code in the Kirigami example app for Android (under LGPL-2) Copyright 2017 Marco Martin
#include <QtAndroid>
// there doesn't appear to be an include that defines these in an easily accessible way
// WindowManager.LayoutParams
#define FLAG_TRANSLUCENT_STATUS 0x04000000

View File

@ -51,7 +51,10 @@ void QMLProfile::paint(QPainter *painter)
timer.start();
// let's look at the intended size of the content and scale our scene accordingly
// for some odd reason the painter transformation is set up to scale by the dpr - which results
// in applying that dpr scaling twice. So we hard-code it here to be the identity matrix
QRect painterRect = painter->viewport();
painter->resetTransform();
if (m_diveId < 0)
return;
struct dive *d = get_dive_by_uniq_id(m_diveId);

View File

@ -221,7 +221,8 @@ echo Building from "$SRC", installing in "$INSTALL_ROOT"
# find qmake
if [ -n "$CMAKE_PREFIX_PATH" ] ; then
QMAKE=$CMAKE_PREFIX_PATH/../../bin/qmake
else
fi
if [[ -z $QMAKE || ! -x $QMAKE ]] ; then
hash qmake > /dev/null 2> /dev/null && QMAKE=qmake
[ -z $QMAKE ] && hash qmake-qt5 > /dev/null 2> /dev/null && QMAKE=qmake-qt5
[ -z $QMAKE ] && echo "cannot find qmake or qmake-qt5" && exit 1