Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qstandardpaths_android.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:provides-trusted-directory-paths
4
6
7#ifndef QT_NO_STANDARDPATHS
8
9#include <QtCore/qjniobject.h>
10#include <QtCore/qmap.h>
11#include <QtCore/qcoreapplication.h>
12#include <QDir>
13
14QT_BEGIN_NAMESPACE
15
16Q_DECLARE_JNI_CLASS(Environment, "android/os/Environment");
17
18using namespace QNativeInterface;
19using namespace Qt::StringLiterals;
20
23
25{
26 return QStandardPaths::isTestModeEnabled() ? "/qttest"_L1 : ""_L1;
27}
28
29static inline QString getAbsolutePath(const QJniObject &file)
30{
31 QJniObject path = file.callMethod<jstring>("getAbsolutePath");
32
33 if (!path.isValid())
34 return QString();
35
36 return path.toString();
37}
38
39/*
40 * The root of the external storage
41 *
42 */
44{
45 QString &path = (*androidDirCache)[QStringLiteral("EXT_ROOT")];
46 if (!path.isEmpty())
47 return path;
48
49 QJniObject file = QJniObject::callStaticMethod<QtJniTypes::File>("android/os/Environment",
50 "getExternalStorageDirectory");
51 if (!file.isValid())
52 return QString();
53
54 return (path = getAbsolutePath(file));
55}
56
57/*
58 * Locations where applications can place user files shared by all apps (public).
59 * E.g., /storage/Music
60 */
61static QString getExternalStoragePublicDirectory(const char *directoryField)
62{
63 QString &path = (*androidDirCache)[QLatin1String(directoryField)];
64 if (!path.isEmpty())
65 return path;
66
67 QJniObject dirField = QJniObject::getStaticField<jstring>("android/os/Environment",
68 directoryField);
69 if (!dirField.isValid())
70 return QString();
71
72 QJniObject file = QJniObject::callStaticMethod<QtJniTypes::File>("android/os/Environment",
73 "getExternalStoragePublicDirectory",
74 dirField.object<jstring>());
75 if (!file.isValid())
76 return QString();
77
78 return (path = getAbsolutePath(file));
79}
80
81/*
82 * Locations where applications can place persistent files it owns.
83 * E.g., /storage/org.app/Music
84 */
85static QString getExternalFilesDir(const char *directoryField = nullptr)
86{
87 QString &path = (*androidDirCache)["APPNAME_%1"_L1.arg(QLatin1StringView(directoryField))];
88 if (!path.isEmpty())
89 return path;
90
91 QJniObject appCtx = QAndroidApplication::context();
92 if (!appCtx.isValid())
93 return QString();
94
95 QJniObject dirField = QJniObject::fromString(""_L1);
96 if (directoryField && strlen(directoryField) > 0) {
97 dirField = QJniObject::getStaticField<QtJniTypes::Environment, jstring>(directoryField);
98 if (!dirField.isValid())
99 return QString();
100 }
101
102 QJniObject file = appCtx.callMethod<QtJniTypes::File>("getExternalFilesDir",
103 dirField.object<jstring>());
104
105 if (!file.isValid())
106 return QString();
107
108 return (path = getAbsolutePath(file));
109}
110
111/*
112 * Directory where applications can store cache files it owns (public).
113 * E.g., /storage/org.app/
114 */
116{
117 QString &path = (*androidDirCache)[QStringLiteral("APPNAME_CACHE")];
118 if (!path.isEmpty())
119 return path;
120
121 QJniObject appCtx = QAndroidApplication::context();
122 if (!appCtx.isValid())
123 return QString();
124
125 QJniObject file = appCtx.callMethod<QtJniTypes::File>("getExternalCacheDir");
126
127 if (!file.isValid())
128 return QString();
129
130 return (path = getAbsolutePath(file));
131}
132
133/*
134 * Directory where applications can store cache files it owns (private).
135 */
137{
138 QString &path = (*androidDirCache)[QStringLiteral("APPROOT_CACHE")];
139 if (!path.isEmpty())
140 return path;
141
142 QJniObject appCtx = QAndroidApplication::context();
143 if (!appCtx.isValid())
144 return QString();
145
146 QJniObject file = appCtx.callMethod<QtJniTypes::File>("getCacheDir");
147 if (!file.isValid())
148 return QString();
149
150 return (path = getAbsolutePath(file));
151}
152
153/*
154 * Directory where applications can store files it owns (private).
155 * (Same location as $HOME)
156 */
158{
159 QString &path = (*androidDirCache)[QStringLiteral("APPROOT_FILES")];
160 if (!path.isEmpty())
161 return path;
162
163 QJniObject appCtx = QAndroidApplication::context();
164 if (!appCtx.isValid())
165 return QString();
166
167 QJniObject file = appCtx.callMethod<QtJniTypes::File>("getFilesDir");
168 if (!file.isValid())
169 return QString();
170
171 return (path = getAbsolutePath(file));
172}
173
174static QString getSdkBasedExternalDir(const char *directoryField = nullptr)
175{
176 return (QNativeInterface::QAndroidApplication::sdkVersion() >= 30)
177 ? getExternalFilesDir(directoryField)
178 : getExternalStoragePublicDirectory(directoryField);
179}
180
181QString QStandardPaths::writableLocation(StandardLocation type)
182{
183 switch (type) {
184 case QStandardPaths::MusicLocation:
185 return getSdkBasedExternalDir("DIRECTORY_MUSIC");
186 case QStandardPaths::MoviesLocation:
187 return getSdkBasedExternalDir("DIRECTORY_MOVIES");
188 case QStandardPaths::PicturesLocation:
189 return getSdkBasedExternalDir("DIRECTORY_PICTURES");
190 case QStandardPaths::DocumentsLocation:
191 return getSdkBasedExternalDir("DIRECTORY_DOCUMENTS");
192 case QStandardPaths::DownloadLocation:
193 return getSdkBasedExternalDir("DIRECTORY_DOWNLOADS");
194 case QStandardPaths::GenericConfigLocation:
195 case QStandardPaths::ConfigLocation:
196 case QStandardPaths::AppConfigLocation:
197 return getFilesDir() + testDir() + "/settings"_L1;
198 case QStandardPaths::StateLocation:
199 case QStandardPaths::GenericStateLocation:
200 return getFilesDir() + testDir() + "/state"_L1;
201 case QStandardPaths::GenericDataLocation:
202 {
203 return QAndroidApplication::sdkVersion() >= 30 ?
204 getExternalFilesDir() + testDir() : getExternalStorageDirectory() + testDir();
205 }
206 case QStandardPaths::AppDataLocation:
207 case QStandardPaths::AppLocalDataLocation:
208 return getFilesDir() + testDir();
209 case QStandardPaths::GenericCacheLocation:
210 case QStandardPaths::RuntimeLocation:
211 case QStandardPaths::TempLocation:
212 case QStandardPaths::CacheLocation:
213 return getCacheDir() + testDir();
214 case QStandardPaths::DesktopLocation:
215 case QStandardPaths::HomeLocation:
216 return getFilesDir();
217 case QStandardPaths::ApplicationsLocation:
218 case QStandardPaths::FontsLocation:
219 case QStandardPaths::PublicShareLocation:
220 case QStandardPaths::TemplatesLocation:
221 default:
222 break;
223 }
224
225 return QString();
226}
227
228QStringList QStandardPaths::standardLocations(StandardLocation type)
229{
230 QStringList locations;
231
232 if (type == MusicLocation) {
233 locations << getExternalFilesDir("DIRECTORY_MUSIC");
234 // Place the public dirs before the app own dirs
235 if (QNativeInterface::QAndroidApplication::sdkVersion() < 30) {
236 locations << getExternalStoragePublicDirectory("DIRECTORY_PODCASTS")
237 << getExternalStoragePublicDirectory("DIRECTORY_NOTIFICATIONS")
238 << getExternalStoragePublicDirectory("DIRECTORY_ALARMS");
239 }
240 locations << getExternalFilesDir("DIRECTORY_PODCASTS")
241 << getExternalFilesDir("DIRECTORY_NOTIFICATIONS")
242 << getExternalFilesDir("DIRECTORY_ALARMS");
243 } else if (type == MoviesLocation) {
244 locations << getExternalFilesDir("DIRECTORY_MOVIES");
245 } else if (type == PicturesLocation) {
246 locations << getExternalFilesDir("DIRECTORY_PICTURES");
247 } else if (type == DocumentsLocation) {
248 locations << getExternalFilesDir("DIRECTORY_DOCUMENTS");
249 } else if (type == DownloadLocation) {
250 locations << getExternalFilesDir("DIRECTORY_DOWNLOADS");
251 } else if (type == AppDataLocation || type == AppLocalDataLocation) {
252 locations << getExternalFilesDir();
253 } else if (type == CacheLocation) {
254 locations << getExternalCacheDir();
255 } else if (type == FontsLocation) {
256 QString &fontLocation = (*androidDirCache)[QStringLiteral("FONT_LOCATION")];
257 if (!fontLocation.isEmpty()) {
258 locations << fontLocation;
259 } else {
260 const QByteArray ba = qgetenv("QT_ANDROID_FONT_LOCATION");
261 if (!ba.isEmpty()) {
262 locations << (fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba)));
263 } else {
264 // Don't cache the fallback, as we might just have been called before
265 // QT_ANDROID_FONT_LOCATION has been set.
266 locations << "/system/fonts"_L1;
267 }
268 }
269 }
270
271 const QString writable = writableLocation(type);
272 if (!writable.isEmpty())
273 locations.prepend(writable);
274
275 locations.removeDuplicates();
276 return locations;
277}
278
279QT_END_NAMESPACE
280
281#endif // QT_NO_STANDARDPATHS
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
static QString getExternalCacheDir()
static QString getExternalStorageDirectory()
QMap< QString, QString > AndroidDirCache
static QString getExternalFilesDir(const char *directoryField=nullptr)
static QString getSdkBasedExternalDir(const char *directoryField=nullptr)
static QString getExternalStoragePublicDirectory(const char *directoryField)
static QString getAbsolutePath(const QJniObject &file)
static QString getCacheDir()
static QString getFilesDir()
static QString testDir()