47 using namespace QtJniTypes;
49 static QMap<QString, QString> triedFonts;
50 const auto it = triedFonts.find(query);
51 if (it != triedFonts.constEnd())
55 triedFonts[query] = fontFamily;
57 QStringList loadedFamilies;
58 if (QFile file(query); file.open(QIODevice::ReadOnly)) {
59 qCDebug(lcIconEngineFontDownload) <<
"Loading font from resource" << query;
60 const QByteArray fontData = file.readAll();
61 int fontId = QFontDatabase::addApplicationFontFromData(fontData);
62 loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
63 }
else if (!query.startsWith(u":/"_s)) {
64 const QString package = u"com.google.android.gms"_s;
65 const QString authority = u"com.google.android.gms.fonts"_s;
68 const auto context = QtAndroidPrivate::context();
70 auto packageManager = context.callMethod<PackageManager>(
"getPackageManager");
71 if (!packageManager.isValid()) {
72 qCWarning(lcIconEngineFontDownload,
"Failed to instantiate PackageManager");
75 const int signaturesField = PackageManager::getStaticField<
int>(
"GET_SIGNATURES");
76 auto providerInfo = packageManager.callMethod<ProviderInfo>(
"resolveContentProvider",
78 if (!providerInfo.isValid()) {
79 qCWarning(lcIconEngineFontDownload,
"Failed to resolve content provider");
82 const QString packageName = providerInfo.getField<QString>(
"packageName");
83 if (packageName != package) {
84 qCWarning(lcIconEngineFontDownload,
"Mismatched provider package - expected '%s', got '%s'",
85 package.toUtf8().constData(), packageName.toUtf8().constData());
88 auto packageInfo = packageManager.callMethod<PackageInfo>(
"getPackageInfo",
89 package, signaturesField);
90 if (!packageInfo.isValid()) {
91 qCWarning(lcIconEngineFontDownload,
"Failed to get package info with signature field %d",
95 const auto signatures = packageInfo.getField<Signature[]>(
"signatures");
96 if (!signatures.isValid()) {
97 qCWarning(lcIconEngineFontDownload,
"Failed to get signature array from package info");
104 Q_ASSERT(outerList.isValid() && innerSet.isValid());
106 for (
const auto &signature : signatures) {
107 const QJniArray<jbyte> byteArray = signature.callMethod<jbyte[]>(
"toByteArray");
110 if (!innerSet.callMethod<jboolean>(
"add", byteArray.object<jobject>()))
111 qCWarning(lcIconEngineFontDownload,
"Failed to add signature to set");
114 if (!outerList.callMethod<jboolean>(
"add", innerSet.object()))
115 qCWarning(lcIconEngineFontDownload,
"Failed to add set to certificate list");
118 FontRequest fontRequest(authority, package, query, outerList.object<List>());
119 if (!fontRequest.isValid()) {
120 qCWarning(lcIconEngineFontDownload,
"Failed to create font request for '%s'",
121 query.toUtf8().constData());
126 auto fontFamilyResult = FontsContractCompat::callStaticMethod<FontFamilyResult>(
129 CancellationSignal(
nullptr),
131 if (!fontFamilyResult.isValid()) {
132 qCWarning(lcIconEngineFontDownload,
"Failed to fetch fonts for query '%s'",
133 query.toUtf8().constData());
137 enum class StatusCode {
139 UNEXPECTED_DATA_PROVIDED = 1,
140 WRONG_CERTIFICATES = 2,
143 const StatusCode statusCode = fontFamilyResult.callMethod<StatusCode>(
"getStatusCode");
144 switch (statusCode) {
147 case StatusCode::UNEXPECTED_DATA_PROVIDED:
148 qCWarning(lcIconEngineFontDownload,
"Provider returned unexpected data for query '%s'",
149 query.toUtf8().constData());
151 case StatusCode::WRONG_CERTIFICATES:
152 qCWarning(lcIconEngineFontDownload,
"Wrong Certificates provided in query '%s'",
153 query.toUtf8().constData());
157 const auto fontInfos = fontFamilyResult.callMethod<FontInfo[]>(
"getFonts");
158 if (!fontInfos.isValid()) {
159 qCWarning(lcIconEngineFontDownload,
"FontFamilyResult::getFonts returned null object for '%s'",
160 query.toUtf8().constData());
164 auto contentResolver = context.callMethod<ContentResolver>(
"getContentResolver");
166 for (QJniObject fontInfo : fontInfos) {
167 if (!fontInfo.isValid()) {
168 qCDebug(lcIconEngineFontDownload,
"Received null-fontInfo object, skipping");
171 enum class ResultCode {
174 FONT_UNAVAILABLE = 2,
177 const ResultCode resultCode = fontInfo.callMethod<ResultCode>(
"getResultCode");
178 switch (resultCode) {
181 case ResultCode::FONT_NOT_FOUND:
182 qCWarning(lcIconEngineFontDownload,
"Font '%s' could not be found",
183 query.toUtf8().constData());
185 case ResultCode::FONT_UNAVAILABLE:
186 qCWarning(lcIconEngineFontDownload,
"Font '%s' is unavailable at",
187 query.toUtf8().constData());
189 case ResultCode::MALFORMED_QUERY:
190 qCWarning(lcIconEngineFontDownload,
"Query string '%s' is malformed",
191 query.toUtf8().constData());
194 auto fontUri = fontInfo.callMethod<Uri>(
"getUri");
197 auto fileDescriptor = contentResolver.callMethod<ParcelFileDescriptor>(
"openFileDescriptor",
199 if (!fileDescriptor.isValid()) {
200 qCWarning(lcIconEngineFontDownload,
"Font file '%s' not accessible",
201 fontUri.toString().toUtf8().constData());
205 int fd = fileDescriptor.callMethod<
int>(
"detachFd");
207 if (!file.open(fd, QFile::OpenModeFlag::ReadOnly,
208 QFile::FileHandleFlag::AutoCloseHandle)) {
209 qCWarning(lcIconEngineFontDownload,
"Font file '%ls' cannot be opened: %ls",
210 qUtf16Printable(fontUri.toString()),
211 qUtf16Printable(file.errorString()));
214 const QByteArray fontData = file.readAll();
215 qCDebug(lcIconEngineFontDownload) <<
"Font file read:" << fontData.size() <<
"bytes";
216 int fontId = QFontDatabase::addApplicationFontFromData(fontData);
217 loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
221 qCDebug(lcIconEngineFontDownload) <<
"Query '" << query <<
"' added families" << loadedFamilies;
222 if (!loadedFamilies.isEmpty())
223 fontFamily = loadedFamilies.first();
224 triedFonts[query] = fontFamily;