46 using namespace QtJniTypes;
48 static QMap<QString, QString> triedFonts;
49 const auto it = triedFonts.find(query);
50 if (it != triedFonts.constEnd())
54 triedFonts[query] = fontFamily;
56 QStringList loadedFamilies;
57 if (QFile file(query); file.open(QIODevice::ReadOnly)) {
58 qCDebug(lcIconEngineFontDownload) <<
"Loading font from resource" << query;
59 const QByteArray fontData = file.readAll();
60 int fontId = QFontDatabase::addApplicationFontFromData(fontData);
61 loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
62 }
else if (!query.startsWith(u":/"_s)) {
63 const QString package = u"com.google.android.gms"_s;
64 const QString authority = u"com.google.android.gms.fonts"_s;
67 const auto context = QtAndroidPrivate::context();
69 auto packageManager = context.callMethod<PackageManager>(
"getPackageManager");
70 if (!packageManager.isValid()) {
71 qCWarning(lcIconEngineFontDownload,
"Failed to instantiate PackageManager");
74 const int signaturesField = PackageManager::getStaticField<
int>(
"GET_SIGNATURES");
75 auto providerInfo = packageManager.callMethod<ProviderInfo>(
"resolveContentProvider",
77 if (!providerInfo.isValid()) {
78 qCWarning(lcIconEngineFontDownload,
"Failed to resolve content provider");
81 const QString packageName = providerInfo.getField<QString>(
"packageName");
82 if (packageName != package) {
83 qCWarning(lcIconEngineFontDownload,
"Mismatched provider package - expected '%s', got '%s'",
84 package.toUtf8().constData(), packageName.toUtf8().constData());
87 auto packageInfo = packageManager.callMethod<PackageInfo>(
"getPackageInfo",
88 package, signaturesField);
89 if (!packageInfo.isValid()) {
90 qCWarning(lcIconEngineFontDownload,
"Failed to get package info with signature field %d",
94 const auto signatures = packageInfo.getField<Signature[]>(
"signatures");
95 if (!signatures.isValid()) {
96 qCWarning(lcIconEngineFontDownload,
"Failed to get signature array from package info");
103 Q_ASSERT(outerList.isValid() && innerSet.isValid());
105 for (
const auto &signature : signatures) {
106 const QJniArray<jbyte> byteArray = signature.callMethod<jbyte[]>(
"toByteArray");
109 if (!innerSet.callMethod<jboolean>(
"add", byteArray.object<jobject>()))
110 qCWarning(lcIconEngineFontDownload,
"Failed to add signature to set");
113 if (!outerList.callMethod<jboolean>(
"add", innerSet.object()))
114 qCWarning(lcIconEngineFontDownload,
"Failed to add set to certificate list");
117 FontRequest fontRequest(authority, package, query, outerList.object<List>());
118 if (!fontRequest.isValid()) {
119 qCWarning(lcIconEngineFontDownload,
"Failed to create font request for '%s'",
120 query.toUtf8().constData());
125 auto fontFamilyResult = FontsContractCompat::callStaticMethod<FontFamilyResult>(
128 CancellationSignal(
nullptr),
130 if (!fontFamilyResult.isValid()) {
131 qCWarning(lcIconEngineFontDownload,
"Failed to fetch fonts for query '%s'",
132 query.toUtf8().constData());
136 enum class StatusCode {
138 UNEXPECTED_DATA_PROVIDED = 1,
139 WRONG_CERTIFICATES = 2,
142 const StatusCode statusCode = fontFamilyResult.callMethod<StatusCode>(
"getStatusCode");
143 switch (statusCode) {
146 case StatusCode::UNEXPECTED_DATA_PROVIDED:
147 qCWarning(lcIconEngineFontDownload,
"Provider returned unexpected data for query '%s'",
148 query.toUtf8().constData());
150 case StatusCode::WRONG_CERTIFICATES:
151 qCWarning(lcIconEngineFontDownload,
"Wrong Certificates provided in query '%s'",
152 query.toUtf8().constData());
156 const auto fontInfos = fontFamilyResult.callMethod<FontInfo[]>(
"getFonts");
157 if (!fontInfos.isValid()) {
158 qCWarning(lcIconEngineFontDownload,
"FontFamilyResult::getFonts returned null object for '%s'",
159 query.toUtf8().constData());
163 auto contentResolver = context.callMethod<ContentResolver>(
"getContentResolver");
165 for (QJniObject fontInfo : fontInfos) {
166 if (!fontInfo.isValid()) {
167 qCDebug(lcIconEngineFontDownload,
"Received null-fontInfo object, skipping");
170 enum class ResultCode {
173 FONT_UNAVAILABLE = 2,
176 const ResultCode resultCode = fontInfo.callMethod<ResultCode>(
"getResultCode");
177 switch (resultCode) {
180 case ResultCode::FONT_NOT_FOUND:
181 qCWarning(lcIconEngineFontDownload,
"Font '%s' could not be found",
182 query.toUtf8().constData());
184 case ResultCode::FONT_UNAVAILABLE:
185 qCWarning(lcIconEngineFontDownload,
"Font '%s' is unavailable at",
186 query.toUtf8().constData());
188 case ResultCode::MALFORMED_QUERY:
189 qCWarning(lcIconEngineFontDownload,
"Query string '%s' is malformed",
190 query.toUtf8().constData());
193 auto fontUri = fontInfo.callMethod<Uri>(
"getUri");
196 auto fileDescriptor = contentResolver.callMethod<ParcelFileDescriptor>(
"openFileDescriptor",
198 if (!fileDescriptor.isValid()) {
199 qCWarning(lcIconEngineFontDownload,
"Font file '%s' not accessible",
200 fontUri.toString().toUtf8().constData());
204 int fd = fileDescriptor.callMethod<
int>(
"detachFd");
206 if (!file.open(fd, QFile::OpenModeFlag::ReadOnly,
207 QFile::FileHandleFlag::AutoCloseHandle)) {
208 qCWarning(lcIconEngineFontDownload,
"Font file '%ls' cannot be opened: %ls",
209 qUtf16Printable(fontUri.toString()),
210 qUtf16Printable(file.errorString()));
213 const QByteArray fontData = file.readAll();
214 qCDebug(lcIconEngineFontDownload) <<
"Font file read:" << fontData.size() <<
"bytes";
215 int fontId = QFontDatabase::addApplicationFontFromData(fontData);
216 loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
220 qCDebug(lcIconEngineFontDownload) <<
"Query '" << query <<
"' added families" << loadedFamilies;
221 if (!loadedFamilies.isEmpty())
222 fontFamily = loadedFamilies.first();
223 triedFonts[query] = fontFamily;