diff options
Diffstat (limited to 'src/plugins/platforms/android/qandroidplatformservices.cpp')
-rw-r--r-- | src/plugins/platforms/android/qandroidplatformservices.cpp | 137 |
1 files changed, 85 insertions, 52 deletions
diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp index 36e1aef609..39287aa905 100644 --- a/src/plugins/platforms/android/qandroidplatformservices.cpp +++ b/src/plugins/platforms/android/qandroidplatformservices.cpp @@ -1,80 +1,98 @@ -/**************************************************************************** -** -** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qandroidplatformservices.h" #include <QDebug> +#include <QDesktopServices> #include <QFile> #include <QMimeDatabase> -#include <QUrl> #include <QtCore/QJniObject> #include <QtCore/qcoreapplication.h> +#include <QtCore/qscopedvaluerollback.h> QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + QAndroidPlatformServices::QAndroidPlatformServices() { + m_actionView = QJniObject::getStaticObjectField("android/content/Intent", "ACTION_VIEW", + "Ljava/lang/String;") + .toString(); + + QtAndroidPrivate::registerNewIntentListener(this); + + // Qt applications without Activity contexts cannot retrieve intents from the Activity. + if (QNativeInterface::QAndroidApplication::isActivityContext()) { + QMetaObject::invokeMethod( + this, + [this] { + QJniObject context = QJniObject(QtAndroidPrivate::context()); + QJniObject intent = + context.callObjectMethod("getIntent", "()Landroid/content/Intent;"); + handleNewIntent(nullptr, intent.object()); + }, + Qt::QueuedConnection); + } } +Q_DECLARE_JNI_CLASS(UriType, "android/net/Uri") +Q_DECLARE_JNI_CLASS(FileType, "java/io/File") +Q_DECLARE_JNI_CLASS(File, "java/io/File") +Q_DECLARE_JNI_CLASS(FileProvider, "androidx/core/content/FileProvider"); + bool QAndroidPlatformServices::openUrl(const QUrl &theUrl) { QString mime; QUrl url(theUrl); + // avoid recursing back into self + if (url == m_handlingUrl) + return false; + // if the file is local, we need to pass the MIME type, otherwise Android // does not start an Intent to view this file - QLatin1String fileScheme("file"); - if ((url.scheme().isEmpty() || url.scheme() == fileScheme) && QFile::exists(url.path())) { - // a real URL including the scheme is needed, else the Intent can not be started + const auto fileScheme = "file"_L1; + + // a real URL including the scheme is needed, else the Intent can not be started + if (url.scheme().isEmpty()) url.setScheme(fileScheme); - QMimeDatabase mimeDb; - mime = mimeDb.mimeTypeForUrl(url).name(); - } + + if (url.scheme() == fileScheme) + mime = QMimeDatabase().mimeTypeForUrl(url).name(); + + const QJniObject mimeString = QJniObject::fromString(mime); using namespace QNativeInterface; - QJniObject urlString = QJniObject::fromString(url.toString()); - QJniObject mimeString = QJniObject::fromString(mime); - return QJniObject::callStaticMethod<jboolean>( - QtAndroid::applicationClass(), "openURL", - "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Z", - QAndroidApplication::context(), urlString.object(), mimeString.object()); + + auto openUrl = [mimeString](const QJniObject &url) { + return QJniObject::callStaticMethod<jboolean>(QtAndroid::applicationClass(), "openURL", + QAndroidApplication::context(), url.object<jstring>(), mimeString.object<jstring>()); + }; + + if (url.scheme() != fileScheme || QNativeInterface::QAndroidApplication::sdkVersion() < 24) + return openUrl(QJniObject::fromString(url.toString())); + + // Use FileProvider for file scheme with sdk >= 24 + const QJniObject context = QAndroidApplication::context(); + const auto appId = context.callMethod<jstring>("getPackageName").toString(); + const auto providerName = QJniObject::fromString(appId + ".qtprovider"_L1); + + const auto urlPath = QJniObject::fromString(url.path()); + const auto urlFile = QJniObject(QtJniTypes::Traits<QtJniTypes::File>::className(), + urlPath.object<jstring>()); + + const auto fileProviderUri = QJniObject::callStaticMethod<QtJniTypes::UriType>( + QtJniTypes::Traits<QtJniTypes::FileProvider>::className(), "getUriForFile", + QAndroidApplication::context(), providerName.object<jstring>(), + urlFile.object<QtJniTypes::FileType>()); + + if (fileProviderUri.isValid()) + return openUrl(fileProviderUri.callMethod<jstring>("toString")); + + return false; } bool QAndroidPlatformServices::openDocument(const QUrl &url) @@ -87,4 +105,19 @@ QByteArray QAndroidPlatformServices::desktopEnvironment() const return QByteArray("Android"); } +bool QAndroidPlatformServices::handleNewIntent(JNIEnv *env, jobject intent) +{ + Q_UNUSED(env); + + const QJniObject jniIntent(intent); + + const QString action = jniIntent.callObjectMethod<jstring>("getAction").toString(); + if (action != m_actionView) + return false; + + const QString url = jniIntent.callObjectMethod<jstring>("getDataString").toString(); + QScopedValueRollback<QUrl> rollback(m_handlingUrl, url); + return QDesktopServices::openUrl(url); +} + QT_END_NAMESPACE |