Compare commits
5 Commits
master
...
shareLogAn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4660ffe29 | ||
|
|
354fb15776 | ||
|
|
95e2ded5a4 | ||
|
|
ad0e346714 | ||
|
|
0629deb4b5 |
@ -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
|
- planner: make ESC (cancel plan) work when moving handles
|
||||||
- dive list: make dive guide visible in dive list [#3382]
|
- dive list: make dive guide visible in dive list [#3382]
|
||||||
- general: rename dive master to dive guide
|
- general: rename dive master to dive guide
|
||||||
|
|||||||
@ -77,6 +77,15 @@
|
|||||||
<meta-data android:name="android.max_aspect" android:value="3" />
|
<meta-data android:name="android.max_aspect" android:value="3" />
|
||||||
|
|
||||||
</activity>
|
</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>
|
</application>
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="21"
|
<uses-sdk android:minSdkVersion="21"
|
||||||
|
|||||||
@ -27,8 +27,9 @@ allprojects {
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
dependencies {
|
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.github.mik3y:usb-serial-for-android:v3.4.3'
|
||||||
|
implementation 'com.android.support:support-v4:25.3.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|||||||
4
android-mobile/res/xml/filepaths.xml
Normal file
4
android-mobile/res/xml/filepaths.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<files-path path="./" name="logfiles" />
|
||||||
|
</paths>
|
||||||
@ -20,10 +20,80 @@ import android.content.Intent;
|
|||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
import android.util.Log;
|
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
|
// this is the main class that will be run at start
|
||||||
public class SubsurfaceMobileActivity extends QtActivity
|
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 isIntentPending;
|
||||||
public static boolean isInitialized;
|
public static boolean isInitialized;
|
||||||
private static final String TAG = "subsurfacedivelog.mobile";
|
private static final String TAG = "subsurfacedivelog.mobile";
|
||||||
|
|||||||
@ -48,7 +48,8 @@ bool subsurface_ignore_font(const char *font)
|
|||||||
static const char *system_default_path_append(const char *append)
|
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
|
// 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)
|
if (append)
|
||||||
path += QString("/%1").arg(append);
|
path += QString("/%1").arg(append);
|
||||||
|
|||||||
@ -55,6 +55,7 @@
|
|||||||
#include "commands/command.h"
|
#include "commands/command.h"
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID)
|
#if defined(Q_OS_ANDROID)
|
||||||
|
#include <QtAndroid>
|
||||||
#include "core/serial_usb_android.h"
|
#include "core/serial_usb_android.h"
|
||||||
std::vector<android_usb_serial_device_descriptor> androidSerialDevices;
|
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) || defined(Q_OS_IOS)
|
||||||
#if defined(Q_OS_ANDROID)
|
#if defined(Q_OS_ANDROID)
|
||||||
// on Android we first try the GenericDataLocation (typically /storage/emulated/0) and if that fails
|
// on Android we first try the AppDataLocation (which allows sharing of files), then the
|
||||||
// (as happened e.g. on a Sony Xperia phone) we try several other default locations, with the TempLocation as last resort
|
// 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 =
|
QStringList fileLocations =
|
||||||
|
QStandardPaths::standardLocations(QStandardPaths::AppDataLocation) +
|
||||||
QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation) +
|
QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation) +
|
||||||
QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation) +
|
QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation) +
|
||||||
QStandardPaths::standardLocations(QStandardPaths::DownloadLocation) +
|
QStandardPaths::standardLocations(QStandardPaths::DownloadLocation) +
|
||||||
@ -260,7 +263,8 @@ QMLManager::QMLManager() :
|
|||||||
appendTextToLog("Successfully opened logfile " + appLogFileName
|
appendTextToLog("Successfully opened logfile " + appLogFileName
|
||||||
+ " at " + QDateTime::currentDateTime().toString());
|
+ " at " + QDateTime::currentDateTime().toString());
|
||||||
// if we were able to write the overall logfile, also write the libdivecomputer logfile
|
// 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
|
// remove the existing libdivecomputer logfile so we don't copy an old one by mistake
|
||||||
QFile libdcLog(libdcLogFileName);
|
QFile libdcLog(libdcLogFileName);
|
||||||
libdcLog.remove();
|
libdcLog.remove();
|
||||||
@ -488,8 +492,25 @@ void QMLManager::copyAppLogToClipboard()
|
|||||||
|
|
||||||
bool QMLManager::createSupportEmail()
|
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";
|
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();
|
mailToLink += getCombinedLogs();
|
||||||
if (QDesktopServices::openUrl(QUrl(mailToLink))) {
|
if (QDesktopServices::openUrl(QUrl(mailToLink))) {
|
||||||
appendTextToLog("OS accepted support email");
|
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
|
//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
|
//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
|
// there doesn't appear to be an include that defines these in an easily accessible way
|
||||||
// WindowManager.LayoutParams
|
// WindowManager.LayoutParams
|
||||||
#define FLAG_TRANSLUCENT_STATUS 0x04000000
|
#define FLAG_TRANSLUCENT_STATUS 0x04000000
|
||||||
|
|||||||
@ -51,7 +51,10 @@ void QMLProfile::paint(QPainter *painter)
|
|||||||
timer.start();
|
timer.start();
|
||||||
|
|
||||||
// let's look at the intended size of the content and scale our scene accordingly
|
// 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();
|
QRect painterRect = painter->viewport();
|
||||||
|
painter->resetTransform();
|
||||||
if (m_diveId < 0)
|
if (m_diveId < 0)
|
||||||
return;
|
return;
|
||||||
struct dive *d = get_dive_by_uniq_id(m_diveId);
|
struct dive *d = get_dive_by_uniq_id(m_diveId);
|
||||||
|
|||||||
@ -221,7 +221,8 @@ echo Building from "$SRC", installing in "$INSTALL_ROOT"
|
|||||||
# find qmake
|
# find qmake
|
||||||
if [ -n "$CMAKE_PREFIX_PATH" ] ; then
|
if [ -n "$CMAKE_PREFIX_PATH" ] ; then
|
||||||
QMAKE=$CMAKE_PREFIX_PATH/../../bin/qmake
|
QMAKE=$CMAKE_PREFIX_PATH/../../bin/qmake
|
||||||
else
|
fi
|
||||||
|
if [[ -z $QMAKE || ! -x $QMAKE ]] ; then
|
||||||
hash qmake > /dev/null 2> /dev/null && QMAKE=qmake
|
hash qmake > /dev/null 2> /dev/null && QMAKE=qmake
|
||||||
[ -z $QMAKE ] && hash qmake-qt5 > /dev/null 2> /dev/null && QMAKE=qmake-qt5
|
[ -z $QMAKE ] && hash qmake-qt5 > /dev/null 2> /dev/null && QMAKE=qmake-qt5
|
||||||
[ -z $QMAKE ] && echo "cannot find qmake or qmake-qt5" && exit 1
|
[ -z $QMAKE ] && echo "cannot find qmake or qmake-qt5" && exit 1
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user