diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml index c5b88960dd9f0e38007673cb57e3ee8c66931ac4..e4e299931b6b1d04ba5003d2a381be2d24d9ef02 100644 --- a/src/android/AndroidManifest.xml +++ b/src/android/AndroidManifest.xml @@ -19,6 +19,7 @@ </intent-filter> <!-- Nootka file associations --> <intent-filter android:icon="@drawable/level" android:label="Nootka level" android:priority="1" > + <action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.PICK" /> @@ -30,6 +31,7 @@ <data android:pathPattern=".*\\.nel" /> </intent-filter> <intent-filter android:icon="@drawable/level" android:label="Nootka level" android:priority="1"> + <action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> @@ -37,6 +39,7 @@ <data android:scheme="https" android:host="*" android:pathPattern=".*\\.nel" /> </intent-filter> <intent-filter> + <action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> @@ -52,6 +55,7 @@ <data android:mimeType="application/nel" android:host="*" android:pathPattern=".*\\.nel" /> </intent-filter>--> <intent-filter android:icon="@drawable/exam" android:label="Nootka exam" android:priority="1" > + <action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.PICK" /> @@ -69,6 +73,7 @@ <data android:mimeType="application/noo" android:host="*" android:pathPattern=".*\\.noo" /> </intent-filter>--> <intent-filter> + <action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> diff --git a/src/android/build.gradle b/src/android/build.gradle index ef416b0b88c1420d7bed0975240c678198aa73c2..b17f77023d18450968e4daaf2065ca4a43c91d8b 100644 --- a/src/android/build.gradle +++ b/src/android/build.gradle @@ -18,6 +18,7 @@ apply plugin: 'com.android.application' dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:support-v4:25.3.1' } android { diff --git a/src/android/res/xml/file_paths.xml b/src/android/res/xml/file_paths.xml new file mode 100644 index 0000000000000000000000000000000000000000..64ab623b81abcd54bf72dddf2db62126192091d5 --- /dev/null +++ b/src/android/res/xml/file_paths.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<paths xmlns:android="http://schemas.android.com/apk/res/android"> + <external-path name="external_files" path="."/> +</paths> diff --git a/src/android/src/net/sf/nootka/TshareExam.java b/src/android/src/net/sf/nootka/TshareExam.java index eef18c42ce65be504c8a48b97c87e16834167916..6cd3b09b3a4e77908587efd14f48fec433e1e698 100644 --- a/src/android/src/net/sf/nootka/TshareExam.java +++ b/src/android/src/net/sf/nootka/TshareExam.java @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2016 by Tomasz Bojczuk * + * Copyright (C) 2016-2019 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -23,31 +23,54 @@ import java.lang.String; import android.content.Intent; import java.io.File; import android.net.Uri; +import android.util.Log; +import android.app.Activity; +import android.os.Build; +import android.os.Build.VERSION_CODES; +/** + * Following module requires Android Support Repository from Android extras installed (through SDK manager) + * There is appropriate information to use it during buid process in + * src/android/build.gradle + */ +import android.support.v4.content.FileProvider; -public class TshareExam + +public class TshareExam extends Activity { - /** + /** * @fn send(String title, String message, String filePath) * Displays chooser dialog to send/share exam file * @p title - is head text of that dialog * @p message - is message content when send by email was chosen. - */ + */ public static void send(String title, String message, String filePath) { if (QtNative.activity() == null) return; + Intent shareIntent = new Intent(Intent.ACTION_SEND); -// shareIntent.setType("application/noo"); shareIntent.setType("*/*"); shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Nootka"); shareIntent.putExtra(Intent.EXTRA_TEXT, message); // We can be sure that file exists - Nootka checked it before File attachment = new File(filePath); - Uri uri = Uri.fromFile(attachment); + Uri uri; + if (Build.VERSION.SDK_INT < 24) { + uri = Uri.fromFile(attachment); + } else { + uri = FileProvider.getUriForFile(QtNative.activity(), "net.sf.nootka.provider", attachment); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } shareIntent.putExtra(Intent.EXTRA_STREAM, uri); - QtNative.activity().startActivity(Intent.createChooser(shareIntent, title)); + try { + QtNative.activity().startActivity(Intent.createChooser(shareIntent, title)); + } catch (Exception e) { + String msgTag = "Send_exam_file_error"; + Log.e(msgTag, e.toString()); + e.printStackTrace(); + } } } diff --git a/src/libs/core/Android/tandroid.cpp b/src/libs/core/Android/tandroid.cpp index 36839fb7dda99c7e788e4195f5f2b39fb5aa6b13..fa8c0f238201f916fcb296f4b7f228777b290a0d 100644 --- a/src/libs/core/Android/tandroid.cpp +++ b/src/libs/core/Android/tandroid.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2015-2016 by Tomasz Bojczuk * + * Copyright (C) 2015-2020 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -22,6 +22,9 @@ #include <QtAndroidExtras/qandroidjnienvironment.h> #include <QtCore/qdatetime.h> #include <QtCore/qfileinfo.h> +#include <QtWidgets/qmessagebox.h> +#include <QtWidgets/qapplication.h> + #include <QtCore/qdebug.h> @@ -47,6 +50,14 @@ int Tandroid::getAPIlevelNr() { } +bool Tandroid::hasWriteAccess() { + if (QtAndroid::androidSdkVersion() < 23) + return true; + else + return QtAndroid::checkPermission(QStringLiteral("android.permission.WRITE_EXTERNAL_STORAGE")) == QtAndroid::PermissionResult::Granted; +} + + QString Tandroid::getExternalPath() { QString extPath; if (getAPIlevelNr() < 19) { // look for SD card only before Kitkat, otherwise it is inaccessible @@ -61,6 +72,15 @@ QString Tandroid::getExternalPath() { } } } + + if(QtAndroid::androidSdkVersion() >= 23) { + const QString PermissionID("android.permission.WRITE_EXTERNAL_STORAGE"); + if (QtAndroid::checkPermission(PermissionID) != QtAndroid::PermissionResult::Granted) { + auto perms = QtAndroid::requestPermissionsSync(QStringList() << PermissionID); + qDebug() << PermissionID << (perms[PermissionID] == QtAndroid::PermissionResult::Granted); + } + } + if (extPath.isEmpty()) extPath = qgetenv("EXTERNAL_STORAGE"); // return primary storage path (device internal) if (!QFileInfo(extPath).isWritable()) { diff --git a/src/libs/core/Android/tandroid.h b/src/libs/core/Android/tandroid.h index d86e26e461b20bf7b8f6e55837ee0de0b89a078a..3aa60bd787764d46d4e7d9b3404fe9c6ff0cebac 100644 --- a/src/libs/core/Android/tandroid.h +++ b/src/libs/core/Android/tandroid.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2015-2016 by Tomasz Bojczuk * + * Copyright (C) 2015-2020 by Tomasz Bojczuk * * seelook@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -20,29 +20,46 @@ #ifndef TANDROID_H #define TANDROID_H + #include <QtCore/qstring.h> + /** * Android functions requiring invoking native methods through JNI */ namespace Tandroid { - /** Sets phone/tablet screen saving disabled. */ + /** + * Sets phone/tablet screen saving disabled. + */ void setScreenLockDisabled(); - /** Returns a number of Android API on a hosting device. */ + /** + * Returns a number of Android API on a hosting device. + */ int getAPIlevelNr(); - /** Returns path to external storage (SD card). */ + /** + * Returns path to external storage (SD card). + */ QString getExternalPath(); - /** Returns command line argument (usually exam/level file name. */ + /** + * @p TRUE when write access to device is granted. API 23 and above + */ + bool hasWriteAccess(); + + /** + * Returns command line argument (usually exam/level file name. + */ QString getRunArgument(); void sendExam(const QString& title, const QString& message, const QString& filePath); - /** Restarts the application by calling java code with delay. - * WARING! Application has to be terminated just after this method. */ + /** + * Restarts the application by calling java code with delay. + * WARING! Application has to be terminated just after this method. + */ void restartNootka(); QString accountName();