8#if QT_CONFIG(desktopservices)
10#include <QDesktopServices>
12#include <QMimeDatabase>
13#include <QtCore/QJniObject>
14#include <QtCore/qcoreapplication.h>
15#include <QtCore/qscopedvaluerollback.h>
23using namespace QtJniTypes;
24using namespace Qt::StringLiterals;
26#if QT_CONFIG(desktopservices)
27static constexpr auto s_defaultScheme =
"file"_L1;
28static constexpr auto s_defaultProvider =
"qtprovider"_L1;
33#if QT_CONFIG(desktopservices)
34 m_actionView = QJniObject::getStaticObjectField(
"android/content/Intent",
"ACTION_VIEW",
38 QtAndroidPrivate::registerNewIntentListener(
this);
41 if (QNativeInterface::QAndroidApplication::isActivityContext()) {
42 QMetaObject::invokeMethod(
45 QJniObject context = QJniObject(QtAndroidPrivate::context());
47 context.callObjectMethod(
"getIntent",
"()Landroid/content/Intent;");
48 handleNewIntent(
nullptr, intent.object());
50 Qt::QueuedConnection);
57 return QByteArray(
"Android");
65#if QT_CONFIG(desktopservices)
66bool QAndroidPlatformServices::openUrl(
const QUrl &theUrl)
71 if (url == m_handlingUrl)
75 if (url.scheme().isEmpty())
76 url.setScheme(s_defaultScheme);
78 const int sdkVersion = QNativeInterface::QAndroidApplication::sdkVersion();
79 if (url.scheme() != s_defaultScheme || sdkVersion < 24 )
81 return openUrlWithFileProvider(url);
84QString QAndroidPlatformServices::getMimeOfUrl(
const QUrl &url)
const
87 if (url.scheme() == s_defaultScheme)
88 mime = QMimeDatabase().mimeTypeForUrl(url).name();
92bool QAndroidPlatformServices::openURL(
const QUrl &url)
const
94 return openURL(url.toString(QUrl::FullyEncoded));
97bool QAndroidPlatformServices::openURL(
const QString &url)
const
99 return QJniObject::callStaticMethod<jboolean>(
100 QtAndroid::applicationClass(),
"openURL",
101 QNativeInterface::QAndroidApplication::context(),
107static QStringList reorderApplicationProvidersFirst(QStringList authorities)
109 std::stable_partition(authorities.begin(), authorities.end(), [](
const QString &authority) {
110 return !authority.endsWith(s_defaultProvider);
115bool QAndroidPlatformServices::openUrlWithFileProvider(
const QUrl &url)
117 const QJniObject context = QNativeInterface::QAndroidApplication::context();
118 const QStringList authorities =
119 reorderApplicationProvidersFirst(getFileProviderAuthorities(context));
120 if (authorities.isEmpty())
124 for (
const QString &authority : authorities) {
125 const QJniObject uri = fileProviderUri(url, authority);
127 return openURL(uri.toString());
132QJniObject QAndroidPlatformServices::fileProviderUri(
const QUrl &url,
133 const QString &authority)
const
135 const auto urlPath = QJniObject::fromString(url.path());
136 const auto urlFile = QJniObject(Traits<File>::className(),
137 urlPath.object<jstring>());
139 return QJniObject::callStaticMethod<Uri>(
140 Traits<FileProvider>::className(),
"getUriForFile",
141 QNativeInterface::QAndroidApplication::context(), authority,
142 urlFile.object<File>());
145QStringList QAndroidPlatformServices::getFileProviderAuthorities(
const QJniObject &context)
const
147 QStringList authorityList;
149 const auto packageManager = context.callMethod<PackageManager>(
"getPackageManager");
150 const auto packageName = context.callMethod<QString>(
"getPackageName");
151 const auto packageInfo = packageManager.callMethod<PackageInfo>(
"getPackageInfo",
154 const auto providersArray = packageInfo.getField<ProviderInfo[]>(
"providers");
156 if (providersArray.isValid()) {
157 const auto className = Traits<FileProvider>::className();
158 for (
const auto &fileProvider : providersArray) {
159 auto providerName = fileProvider.getField<QString>(
"name");
160 if (providerName.replace(
".",
"/").contains(className.data())) {
161 const auto authority = fileProvider.getField<QString>(
"authority");
162 if (!authority.isEmpty())
163 authorityList << authority;
167 if (authorityList.isEmpty())
168 qWarning() <<
"No file provider found in the AndroidManifest.xml.";
170 return authorityList;
173bool QAndroidPlatformServices::openDocument(
const QUrl &url)
178bool QAndroidPlatformServices::handleNewIntent(JNIEnv *env, jobject intent)
182 const QJniObject jniIntent(intent);
184 const QString action = jniIntent.callObjectMethod<jstring>(
"getAction").toString();
185 if (action != m_actionView)
188 const QString url = jniIntent.callObjectMethod<jstring>(
"getDataString").toString();
189 QScopedValueRollback<QUrl> rollback(m_handlingUrl, url);
190 return QDesktopServices::openUrl(url);
Combined button and popup list for selecting options.
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")