diff --git a/shared_storage/sharedstorage.cpp b/shared_storage/sharedstorage.cpp index dab4a16..18d62fd 100644 --- a/shared_storage/sharedstorage.cpp +++ b/shared_storage/sharedstorage.cpp @@ -18,6 +18,7 @@ const QLatin1String ACTION_OPEN_DOCUMENT("android.intent.action.OPEN_DOCUMENT"); const QLatin1String ACTION_OPEN_DOCUMENT_TREE("android.intent.action.OPEN_DOCUMENT_TREE"); const QLatin1String CATEGORY_OPENABLE("android.intent.category.OPENABLE"); const QLatin1String EXTRA_MIME_TYPES("android.intent.extra.MIME_TYPES"); +const QLatin1String EXTRA_ALLOW_MULTIPLE("android.intent.extra.ALLOW_MULTIPLE"); const QLatin1String EXTRA_TITLE("android.intent.extra.TITLE"); constexpr int RESULT_OK = 0xffffffff; @@ -37,7 +38,7 @@ QJniObject createDocument(const QString &mimeType, const QString &title, const Q return intent; } -QJniObject openDocument(const QStringList &mimeTypes, const QString &initialUri) +QJniObject openDocument(const QStringList &mimeTypes, const QString &initialUri, bool allowMultiple) { QJniObject intent{"android.content.Intent", "(Ljava/lang/String;)V", QJniObject::fromString(ACTION_OPEN_DOCUMENT).object()}; intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", QJniObject::fromString(CATEGORY_OPENABLE).object()); @@ -50,6 +51,11 @@ QJniObject openDocument(const QStringList &mimeTypes, const QString &initialUri) QJniObject::getStaticObjectField("android/provider/DocumentsContract", "EXTRA_INITIAL_URI", "Ljava/lang/String;").object(), QJniObject::fromString(initialUri).object()); } + if (allowMultiple) { + intent.callObjectMethod("putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;", + QJniObject::fromString(EXTRA_ALLOW_MULTIPLE).object(), + static_cast(true)); + } return intent; } @@ -64,6 +70,26 @@ QJniObject openDocumentTree(const QString &initialUri) return intent; } +QList getUrisFromIntent(const QJniObject &intent) { + auto uris = QList(); + auto clipData = intent.callObjectMethod("getClipData", "()Landroid/content/ClipData;"); + auto singleUri = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); + if (clipData.isValid()) { + // User selected multiple files + auto itemCount = clipData.callMethod("getItemCount"); + for (int i = 0; i < itemCount; i++) { + auto item = clipData.callObjectMethod("getItemAt", "(I)Landroid/content/ClipData$Item;", i); + if (item.isValid()) { + auto uri = item.callObjectMethod("getUri", "()Landroid/net/Uri;"); + uris.push_back(uri); + } + } + } else if (singleUri.isValid()) { + // User selected single file + uris.push_back(singleUri); + } + return uris; +} } namespace android { @@ -86,13 +112,22 @@ void SharedStorage::createDocument(int requestCode, RequestResultCallback callba void SharedStorage::openDocument(int requestCode, const RequestResultCallback &callback, const QStringList &mimeTypes, const QString &initialUri) { - startActivity(::openDocument(mimeTypes, initialUri), requestCode, + startActivity(::openDocument(mimeTypes, initialUri, false /* allowMultiple */), requestCode, [requestCode, callback, this](int requestId, int resultCode, QJniObject data) { if (requestCode == requestId && resultCode == RESULT_OK) QMetaObject::invokeMethod(this, [=]{callback(requestId, data.callObjectMethod("getData", "()Landroid/net/Uri;"));}, Qt::QueuedConnection); }); } +void SharedStorage::openDocuments(int requestCode, const RequestMultipleResultsCallback &callback, const QStringList &mimeTypes, const QString &initialUri) +{ + startActivity(::openDocument(mimeTypes, initialUri, true /* allowMultiple */), requestCode, + [requestCode, callback, this](int requestId, int resultCode, QJniObject data) { + if (requestCode == requestId && resultCode == RESULT_OK) + QMetaObject::invokeMethod(this, [=]{callback(requestId, ::getUrisFromIntent(data));}, Qt::QueuedConnection); + }); +} + void SharedStorage::openDocumentTree(int requestCode, const RequestResultCallback &callback, const QString &initialUri) { startActivity(::openDocumentTree(initialUri), requestCode, @@ -112,12 +147,20 @@ void SharedStorage::createDocument(int requestCode, const QString &mimeType, con void SharedStorage::openDocument(int requestCode, const QStringList &mimeTypes, const QString &initialUri) { - startActivity(::openDocument(mimeTypes, initialUri), requestCode, [requestCode, this](int requestId, int resultCode, QJniObject data) { + startActivity(::openDocument(mimeTypes, initialUri, false /* allowMultiple */), requestCode, [requestCode, this](int requestId, int resultCode, QJniObject data) { if (requestCode == requestId && resultCode == RESULT_OK) QMetaObject::invokeMethod(this, [=]{emit requestResult(requestId, data.callObjectMethod("getData", "()Landroid/net/Uri;"));}); }); } +void SharedStorage::openDocuments(int requestCode, const QStringList &mimeTypes, const QString &initialUri) +{ + startActivity(::openDocument(mimeTypes, initialUri, true /* allowMultiple */), requestCode, [requestCode, this](int requestId, int resultCode, QJniObject data) { + if (requestCode == requestId && resultCode == RESULT_OK) + QMetaObject::invokeMethod(this, [=]{emit requestResults(requestId, ::getUrisFromIntent(data));}); + }); +} + void SharedStorage::openDocumentTree(int requestCode, const QString &initialUri) { startActivity(::openDocumentTree(initialUri), requestCode, [requestCode, this](int requestId, int resultCode, QJniObject data) { diff --git a/shared_storage/sharedstorage.h b/shared_storage/sharedstorage.h index 64f5ced..f618c58 100644 --- a/shared_storage/sharedstorage.h +++ b/shared_storage/sharedstorage.h @@ -26,18 +26,22 @@ class SharedStorage : public QObject public: static SharedStorage &instance(); using RequestResultCallback = std::function; + using RequestMultipleResultsCallback = std::function)>; void createDocument(int requestCode, RequestResultCallback callback, const QString &mimeType, const QString &displayName, const QString &initialUri = {}); void openDocument(int requestCode, const RequestResultCallback &callback, const QStringList &mimeTypes, const QString &initialUri = {}); + void openDocuments(int requestCode, const RequestMultipleResultsCallback &callback, const QStringList &mimeTypes, const QString &initialUri = {}); void openDocumentTree(int requestCode, const RequestResultCallback &callback, const QString &initialUri = {}); public slots: void createDocument(int requestCode, const QString &mimeType, const QString &displayName, const QString &initialUri = {}); void openDocument(int requestCode, const QStringList &mimeTypes, const QString &initialUri = {}); + void openDocuments(int requestCode, const QStringList &mimeTypes, const QString &initialUri = {}); void openDocumentTree(int requestCode, const QString &initialUri = {}); signals: void requestResult(int requestId, net::Uri uri); + void requestResults(int requestId, QList uris); }; } // namespace provider