Commit 25860484 authored by Karel Slaný's avatar Karel Slaný

Merge branch 'android-email' into 'develop'

Allow to send email with attachments on Android

Closes #138

See merge request !144
parents c771929e 9b271b90
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#include <QtAndroidExtras> #include <QtAndroidExtras>
#include <QDesktopServices> #include <QDesktopServices>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl> #include <QUrl>
#include "android/src/android_io.h" #include "android/src/android_io.h"
...@@ -44,7 +47,6 @@ bool AndroidIO::isSDKVersion24OrNewest(void) ...@@ -44,7 +47,6 @@ bool AndroidIO::isSDKVersion24OrNewest(void)
bool AndroidIO::openFile(const QString &filePath) bool AndroidIO::openFile(const QString &filePath)
{ {
/* /*
* TODO - must be tested and reimplement. * TODO - must be tested and reimplement.
* Use file provider only because SDK detection fails. * Use file provider only because SDK detection fails.
...@@ -68,8 +70,29 @@ bool AndroidIO::openWithFileProvider(const QString &filePath) ...@@ -68,8 +70,29 @@ bool AndroidIO::openWithFileProvider(const QString &filePath)
QAndroidJniObject jsPath = QAndroidJniObject::fromString(filePath); QAndroidJniObject jsPath = QAndroidJniObject::fromString(filePath);
jboolean ok = QAndroidJniObject::callStaticMethod<jboolean>( jboolean ok = QAndroidJniObject::callStaticMethod<jboolean>(
"cz/nic/mobiledatovka/java/QFileProvider", "cz/nic/mobiledatovka/java/QFileProvider",
"viewFile", "(Ljava/lang/String;I)Z", "viewFile", "(Ljava/lang/String;)Z",
jsPath.object<jstring>(), 0); jsPath.object<jstring>());
return (ok);
}
bool AndroidIO::createEmail(const QString &subject, const QString &to,
const QString &body, const QStringList &filePaths)
{
QAndroidJniObject jsSubject = QAndroidJniObject::fromString(subject);
QAndroidJniObject jsTo = QAndroidJniObject::fromString(to);
QAndroidJniObject jsBody = QAndroidJniObject::fromString(body);
QJsonArray arr = QJsonArray::fromStringList(filePaths);
QJsonObject jsonObj;
jsonObj[QLatin1String("attachments")] = arr;
QJsonDocument doc(jsonObj);
QAndroidJniObject jsJsonPathList = QAndroidJniObject::fromString(doc.toJson(QJsonDocument::Compact));
jboolean ok = QAndroidJniObject::callStaticMethod<jboolean>(
"cz/nic/mobiledatovka/java/QFileProvider",
"sendEmail", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
jsSubject.object<jstring>(), jsTo.object<jstring>(),
jsBody.object<jstring>(), jsJsonPathList.object<jstring>());
return (ok); return (ok);
} }
...@@ -59,6 +59,19 @@ public: ...@@ -59,6 +59,19 @@ public:
static static
bool openFile(const QString &filePath); bool openFile(const QString &filePath);
/*!
* @brief Create email.
*
* @param[in] subject Email subject.
* @param[in] to Email recipient.
* @param[in] body Email body text.
* @param[in] filePaths Attachments paths.
* @return True if success.
*/
static
bool createEmail(const QString &subject, const QString &to,
const QString &body, const QStringList &filePaths);
private: private:
/*! /*!
......
...@@ -53,6 +53,8 @@ import android.os.Build; ...@@ -53,6 +53,8 @@ import android.os.Build;
import android.support.v4.content.FileProvider; import android.support.v4.content.FileProvider;
import android.support.v4.app.ShareCompat; import android.support.v4.app.ShareCompat;
import org.json.*;
public class QFileProvider public class QFileProvider
{ {
// Authority defined in AndroidManifest.xml // Authority defined in AndroidManifest.xml
...@@ -128,7 +130,7 @@ public class QFileProvider ...@@ -128,7 +130,7 @@ public class QFileProvider
return false; return false;
} }
public static boolean viewFile(String filePath, int id) { public static boolean viewFile(String filePath) {
if (QtNative.activity() == null) { if (QtNative.activity() == null) {
return false; return false;
...@@ -160,4 +162,62 @@ public class QFileProvider ...@@ -160,4 +162,62 @@ public class QFileProvider
return startActivity(viewIntent, uri); return startActivity(viewIntent, uri);
} }
public static boolean sendEmail(String subject, String to, String body, String filePathsJson) {
if (QtNative.activity() == null) {
return false;
}
ArrayList<Uri> uris = new ArrayList<Uri>();
try {
JSONObject jsonObj = new JSONObject(filePathsJson);
JSONArray attachments = jsonObj.getJSONArray("attachments");
for (int i=0; i<attachments.length(); i++) {
File attachment = new File(attachments.getString(i));
if (!attachment.exists() || !attachment.canRead()) {
System.out.println("FileProvider: Cannot read file " + attachment);
return false;
}
Uri uri;
try {
uri = FileProvider.getUriForFile(QtNative.activity(), AUTHORITY, attachment);
uris.add(uri);
} catch (IllegalArgumentException ex) {
System.out.println("FileProvider: " + ex.getMessage());
return false;
}
}
} catch (JSONException ex) {
System.out.println("JSONException: " + ex.getMessage());
return false;
}
Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
emailIntent.setType("plain/text");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {to});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
try {
Intent i = Intent.createChooser(emailIntent, "Send mail...");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
QtNative.activity().startActivity(i);
} catch (android.content.ActivityNotFoundException ex) {
System.out.println("There are no email clients installed.");
return false;
} catch (java.lang.RuntimeException ex) {
System.out.println("RuntimeException: " + ex.getMessage());
return false;
} catch (java.lang.Exception ex) {
System.out.println("Exception: " + ex.getMessage());
return false;
}
System.out.println("Email has created.");
return true;
}
} }
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include <QObject> #include <QObject>
#include <QUrl> #include <QUrl>
#if defined (Q_OS_ANDROID)
#include "android/src/android_io.h"
#endif
#include "ios/src/url_opener.h" #include "ios/src/url_opener.h"
#include "src/auxiliaries/email_helper.h" #include "src/auxiliaries/email_helper.h"
#include "src/io/filesystem.h" #include "src/io/filesystem.h"
...@@ -132,8 +135,12 @@ void sendEmail(const QString &emailMessage, const QStringList &fileList, ...@@ -132,8 +135,12 @@ void sendEmail(const QString &emailMessage, const QStringList &fileList,
#elif defined Q_OS_ANDROID #elif defined Q_OS_ANDROID
QDesktopServices::openUrl(QUrl("mailto:" + to + "?" AndroidIO::createEmail(subject, to, body, fileList);
+ "subject=" + subject + "&body=" + body));
// Old send message method for android.
// It creates email without attachments.
//QDesktopServices::openUrl(QUrl("mailto:" + to + "?"
// + "subject=" + subject + "&body=" + body));
#else #else
......
...@@ -200,22 +200,7 @@ void Files::openAttachment(const QString &fileName, ...@@ -200,22 +200,7 @@ void Files::openAttachment(const QString &fileName,
QString docLocationRoot = appTmpDirPath(); QString docLocationRoot = appTmpDirPath();
#if defined (Q_OS_ANDROID) #if defined (Q_OS_ANDROID)
docLocationRoot = getAndroidFileProviderBasePath();
docLocationRoot = QStandardPaths::standardLocations(
QStandardPaths::AppDataLocation).value(0);
QString documentsWorkPath = docLocationRoot.append("/share_example_x_files");
if (!QDir(documentsWorkPath).exists()) {
if (!QDir("").mkpath(documentsWorkPath)) {
logErrorNL("Failed to create share directory: '%s'.",
documentsWorkPath.toUtf8().constData());
Dialogues::errorMessage(Dialogues::CRITICAL,
tr("Open attachment error"),
tr("Cannot save selected file to disk for opening."),
QString());
return;
}
}
#endif #endif
QString filePath(writeFile(docLocationRoot, fileName, binaryData)); QString filePath(writeFile(docLocationRoot, fileName, binaryData));
...@@ -358,6 +343,10 @@ void Files::sendMsgFilesWithEmail(const QString &userName, qint64 msgId, ...@@ -358,6 +343,10 @@ void Files::sendMsgFilesWithEmail(const QString &userName, qint64 msgId,
boundary); boundary);
QStringList filePathList; QStringList filePathList;
#if defined (Q_OS_ANDROID)
targetPath = getAndroidFileProviderBasePath();
#endif
/* Write attachment files to email directory */ /* Write attachment files to email directory */
foreach (const Isds::Document &document, documents) { foreach (const Isds::Document &document, documents) {
QString fileName = document.fileDescr(); QString fileName = document.fileDescr();
...@@ -604,6 +593,10 @@ void Files::sendAttachmentEmailZfo(const QVariant &attachModelVariant, ...@@ -604,6 +593,10 @@ void Files::sendAttachmentEmailZfo(const QVariant &attachModelVariant,
removeDirFromDocLoc(DATOVKA_MAIL_DIR_NAME); removeDirFromDocLoc(DATOVKA_MAIL_DIR_NAME);
QString targetPath(appEmailDirPath(msgIdStr)); QString targetPath(appEmailDirPath(msgIdStr));
#if defined (Q_OS_ANDROID)
targetPath = getAndroidFileProviderBasePath();
#endif
for (int row = 0; row < attachModel->rowCount(); ++row) { for (int row = 0; row < attachModel->rowCount(); ++row) {
QModelIndex idx(attachModel->index(row)); QModelIndex idx(attachModel->index(row));
/* /*
......
...@@ -272,3 +272,24 @@ QString constructLogFileName(void) { ...@@ -272,3 +272,24 @@ QString constructLogFileName(void) {
+ ".log"); + ".log");
return appLogDirPath() + QDir::separator() + logFileName; return appLogDirPath() + QDir::separator() + logFileName;
} }
QString getAndroidFileProviderBasePath(void) {
QString basePath = QStandardPaths::standardLocations(
QStandardPaths::AppDataLocation).value(0);
QString fileProviderDir = basePath.append("/share_example_x_files");
QDir dir(fileProviderDir);
dir.removeRecursively();
if (!QDir(fileProviderDir).exists()) {
if (!QDir("").mkpath(fileProviderDir)) {
logErrorNL("Failed to create share directory: '%s'.",
fileProviderDir.toUtf8().constData());
return QString();
}
}
return basePath;
}
...@@ -190,3 +190,10 @@ void deleteOldestLogFile(void); ...@@ -190,3 +190,10 @@ void deleteOldestLogFile(void);
* @return Full path including log file name. * @return Full path including log file name.
*/ */
QString constructLogFileName(void); QString constructLogFileName(void);
/*!
* @brief Return Android file provider base path.
*
* @return Android file provider base path.
*/
QString getAndroidFileProviderBasePath(void);
...@@ -104,6 +104,11 @@ void Log::sendLogViaEmail(const QString &logContent) ...@@ -104,6 +104,11 @@ void Log::sendLogViaEmail(const QString &logContent)
removeDirFromDocLoc(DATOVKA_MAIL_DIR_NAME); removeDirFromDocLoc(DATOVKA_MAIL_DIR_NAME);
QString targetPath(appEmailDirPath("Log")); QString targetPath(appEmailDirPath("Log"));
#if defined (Q_OS_ANDROID)
targetPath = getAndroidFileProviderBasePath();
#endif
QString filePath(writeFile(targetPath, "mobile-datovka.log", QString filePath(writeFile(targetPath, "mobile-datovka.log",
logContent.toUtf8())); logContent.toUtf8()));
QStringList attachmentList; QStringList attachmentList;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment