diff --git a/src/android/src/de/akaflieg_freiburg/enroute/MobileAdaptor.java b/src/android/src/de/akaflieg_freiburg/enroute/MobileAdaptor.java index 9a636cd12..b4c23303e 100644 --- a/src/android/src/de/akaflieg_freiburg/enroute/MobileAdaptor.java +++ b/src/android/src/de/akaflieg_freiburg/enroute/MobileAdaptor.java @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2019-2024 by Stefan Kebekus, stefan.kebekus@gmail.com * + * Copyright (C) 2019-2025 by Stefan Kebekus, stefan.kebekus@gmail.com * * Copyright (C) 2020 by Johannes Zellner, johannes@zellner.org * * * * This program is free software; you can redistribute it and/or modify * @@ -82,6 +82,8 @@ public class MobileAdaptor extends de.akaflieg_freiburg.enroute.ShareActivity { private static String AUTHORITY = "de.akaflieg_freiburg.enroute"; private static String TAG = "IntentLauncher"; + private static final int PICK_FILE_REQUEST = 1; + public MobileAdaptor() { m_instance = this; } @@ -441,6 +443,44 @@ private static boolean openInGoogleEarth(String geoUrl) { return true; } + /** + * Open a file picker to select a file. + * + * This method opens a file picker to select a file of a given mime type. This is necessary + * to work around a bug in Qt which does not allow to select files with a specific extension + * and does not support remote files. + * + * https://bugreports.qt.io/browse/QTBUG-118154 + * + * @param mimeType the mime type of the file to select. + * + */ + public void openFilePicker(String mimeType) { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + if (!mimeType.isEmpty()) { + intent.setType(mimeType); + } else { + intent.setType("*/*"); + } + startActivityForResult(intent, PICK_FILE_REQUEST); + } + + /** Result of file picking + */ + public static native void setFileReceived(String fileName); + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == PICK_FILE_REQUEST && resultCode == RESULT_OK) { + Uri uri = data.getData(); + if (uri != null) { + setFileReceived(uri.toString()); + } + } + super.onActivityResult(requestCode, resultCode, data); + } + /** * create uri from file path. * diff --git a/src/platform/FileExchange_Android.cpp b/src/platform/FileExchange_Android.cpp index 0fa4e999c..5adb7fa78 100644 --- a/src/platform/FileExchange_Android.cpp +++ b/src/platform/FileExchange_Android.cpp @@ -122,6 +122,16 @@ QString Platform::FileExchange::viewContent(const QByteArray& content, const QSt } +void Platform::FileExchange::openFilePicker(const QString& mime) +{ + const QJniObject activity = QNativeInterface::QAndroidApplication::context(); + if (activity.isValid()) { + const QJniObject mimeTypeStr = QJniObject::fromString(mime); + activity.callMethod("openFilePicker", "(Ljava/lang/String;)V", mimeTypeStr.object()); + } +} + + // // Private Methods // @@ -169,7 +179,7 @@ bool Platform::FileExchange::outgoingIntent(const QString& methodName, const QSt extern "C" { -JNIEXPORT void JNICALL Java_de_akaflieg_1freiburg_enroute_ShareActivity_setFileReceived(JNIEnv* env, jobject /*unused*/, jstring jfname) +JNIEXPORT void JNICALL Java_de_akaflieg_1freiburg_enroute_MobileAdaptor_setFileReceived(JNIEnv* env, jobject /*unused*/, jstring jfname) { const char* fname = env->GetStringUTFChars(jfname, nullptr); @@ -181,6 +191,17 @@ JNIEXPORT void JNICALL Java_de_akaflieg_1freiburg_enroute_ShareActivity_setFileR env->ReleaseStringUTFChars(jfname, fname); } +JNIEXPORT void JNICALL Java_de_akaflieg_1freiburg_enroute_ShareActivity_setFileReceived(JNIEnv* env, jobject /*unused*/, jstring jfname) +{ + const char* fname = env->GetStringUTFChars(jfname, nullptr); + + // A little complicated because GlobalObject::fileExchange() lives in a different thread + QMetaObject::invokeMethod( GlobalObject::fileExchange(), + "processFileOpenRequest", + Qt::QueuedConnection, + Q_ARG( QString, QString::fromUtf8(fname)) ); + env->ReleaseStringUTFChars(jfname, fname); +} JNIEXPORT void JNICALL Java_de_akaflieg_1freiburg_enroute_ShareActivity_setTextReceived(JNIEnv* env, jobject /*unused*/, jstring jfname) { diff --git a/src/platform/FileExchange_Android.h b/src/platform/FileExchange_Android.h index 83185db79..53d706b52 100644 --- a/src/platform/FileExchange_Android.h +++ b/src/platform/FileExchange_Android.h @@ -72,6 +72,8 @@ class FileExchange : public Platform::FileExchange_Abstract */ QString viewContent(const QByteArray& content, const QString& mimeType, const QString& fileNameTemplate) override; +#warning + Q_INVOKABLE static void openFilePicker(const QString& mime); public slots: /*! \brief Implements pure virtual method from FileExchange_Abstract */ @@ -101,7 +103,7 @@ public slots: static bool outgoingIntent(const QString& methodName, const QString& filePath, const QString& mimeType); bool receiveOpenFileRequestsStarted {false}; - QString pendingReceiveOpenFileRequest {}; + QString pendingReceiveOpenFileRequest; }; } // namespace Platform diff --git a/src/qml/main.qml b/src/qml/main.qml index 62b8273ff..bff10ab25 100644 --- a/src/qml/main.qml +++ b/src/qml/main.qml @@ -1003,7 +1003,7 @@ AppWindow { // solution from // see https://stackoverflow.com/questions/25968661/android-back-button-press-doesnt-trigger-keys-onreleased-qml // - onClosing: { + function onClosing (close) { // Use this hack only on the Android platform if (Qt.platform.os !== "android") return diff --git a/src/qml/pages/FlightRouteEditor.qml b/src/qml/pages/FlightRouteEditor.qml index 9d4a66397..04db2deb0 100644 --- a/src/qml/pages/FlightRouteEditor.qml +++ b/src/qml/pages/FlightRouteEditor.qml @@ -267,6 +267,9 @@ Page { text: qsTr("Locate your file in the browser, then select 'Open with' from the share menu, and choose Enroute"), standardButtons: Dialog.Ok}) Global.dialogLoader.active = true + } else if (isAndroid) { + console.log("AA") + FileExchange.openFilePicker("") } else { importFileDialog.open() }