diff --git a/.github/build.sh b/.github/build.sh
index 8e17c3c93..452034477 100755
--- a/.github/build.sh
+++ b/.github/build.sh
@@ -369,7 +369,6 @@ zipalign = andriod_sdk_build_tools / 'zipalign'
apksigner = andriod_sdk_build_tools / 'apksigner'
ANDROID_INI
meson_configure+=$'\t'--cross-file=.github/android-ghactions.ini
- meson_configure+=$'\t'-Dhttp=false
fi
meson_configure+=$'\t'-Dc_args=[$c_args]
meson_configure+=$'\t'-Dcpp_args=[$c_args]
diff --git a/android/AndroidManifest.template.xml b/android/AndroidManifest.template.xml
index 9f998578b..68ce6bbdc 100644
--- a/android/AndroidManifest.template.xml
+++ b/android/AndroidManifest.template.xml
@@ -33,7 +33,7 @@
android:name="android.hardware.type.pc"
android:required="false"
/>
-
+ @ANDROID_PERMISSIONS@
aliases = ks.aliases();
+ while (aliases.hasMoreElements()) {
+ String alias = (String)aliases.nextElement();
+ java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate)ks.getCertificate(alias);
+ allPems += "-----BEGIN CERTIFICATE-----\n" + Base64.getMimeEncoder().encodeToString(cert.getEncoded()) + "\n-----END CERTIFICATE-----\n";;
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return "";
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ return "";
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return "";
+ } catch (java.security.cert.CertificateException e) {
+ e.printStackTrace();
+ return "";
+ }
+ return allPems;
+ }
}
diff --git a/meson.build b/meson.build
index cf9776775..a3b96320f 100644
--- a/meson.build
+++ b/meson.build
@@ -173,9 +173,6 @@ elif lua_variant == 'luajit'
endif
enable_http = get_option('http')
-if host_platform == 'android'
- enable_http = false
-endif
if host_platform == 'android'
android_ndk_toolchain_prefix = meson.get_external_property('android_ndk_toolchain_prefix')
android_platform = meson.get_external_property('android_platform')
diff --git a/src/client/http/requestmanager/AndroidCertProvider.cpp b/src/client/http/requestmanager/AndroidCertProvider.cpp
new file mode 100644
index 000000000..63ef6ccd9
--- /dev/null
+++ b/src/client/http/requestmanager/AndroidCertProvider.cpp
@@ -0,0 +1,86 @@
+#include "CurlError.h"
+#include "common/String.h"
+#include "Config.h"
+#include
+#include
+#include
+#include
+
+static jclass FindClass(JNIEnv *env, const char *name)
+{
+ jobject nativeActivity = (jobject)SDL_AndroidGetActivity(); if (!nativeActivity) return NULL;
+ jclass acl = env->GetObjectClass(nativeActivity); if (!acl ) return NULL;
+ jmethodID getClassLoader = env->GetMethodID(acl, "getClassLoader", "()Ljava/lang/ClassLoader;"); if (!getClassLoader) return NULL;
+ jobject cls = env->CallObjectMethod(nativeActivity, getClassLoader); if (!cls ) return NULL;
+ jclass classLoader = env->FindClass("java/lang/ClassLoader"); if (!classLoader ) return NULL;
+ jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); if (!findClass ) return NULL;
+ jstring strClassName = env->NewStringUTF(name); if (!strClassName ) return NULL;
+ jclass clazz = (jclass)(env->CallObjectMethod(cls, findClass, strClassName));
+ env->DeleteLocalRef(strClassName);
+ return clazz;
+}
+
+namespace http
+{
+ void UseSystemCertProvider(CURL *easy)
+ {
+ struct DoOnce
+ {
+ ByteString allPems;
+
+ void InitPem()
+ {
+ auto die = [](ByteString message) {
+ __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "%s", ("failed to enumerate system certificates: " + message).c_str());
+ };
+ auto *env = (JNIEnv *)SDL_AndroidGetJNIEnv();
+ if (!env)
+ {
+ return die("SDL_AndroidGetJNIEnv failed");
+ }
+ jclass mPowderActivity = FindClass(env, ByteString::Build(APPID, ".PowderActivity").c_str());
+ if (!mPowderActivity)
+ {
+ return die("FindClass failed");
+ }
+ jmethodID midGetCertificateBundle = env->GetStaticMethodID(mPowderActivity, "getCertificateBundle", "()Ljava/lang/String;");
+ if (!midGetCertificateBundle)
+ {
+ return die("GetStaticMethodID failed");
+ }
+ jstring str = (jstring)env->CallStaticObjectMethod(mPowderActivity, midGetCertificateBundle);
+ if (!str)
+ {
+ return die("getCertificateBundle failed");
+ }
+ const char *utf = env->GetStringUTFChars(str, 0);
+ if (utf)
+ {
+ allPems = utf;
+ env->ReleaseStringUTFChars(str, utf);
+ }
+ else
+ {
+ __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "out of memory???");
+ }
+ env->DeleteLocalRef(str);
+ __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "certificate bundle loaded");
+ }
+
+ DoOnce()
+ {
+ InitPem();
+ }
+ };
+
+ static DoOnce doOnce;
+ if (doOnce.allPems.size())
+ {
+ curl_blob blob;
+ blob.data = &doOnce.allPems[0];
+ blob.len = doOnce.allPems.size();
+ blob.flags = CURL_BLOB_COPY;
+ HandleCURLcode(curl_easy_setopt(easy, CURLOPT_CAINFO_BLOB, &blob));
+ }
+ }
+}
diff --git a/src/client/http/requestmanager/meson.build b/src/client/http/requestmanager/meson.build
index c2de3e7b1..94ae54646 100644
--- a/src/client/http/requestmanager/meson.build
+++ b/src/client/http/requestmanager/meson.build
@@ -13,6 +13,10 @@ else
use_system_cert_provider = true
client_files += files('WindowsCertProvider.cpp')
endif
+ if host_platform == 'android'
+ use_system_cert_provider = true
+ client_files += files('AndroidCertProvider.cpp')
+ endif
endif
conf_data.set('NOHTTP', (not enable_http).to_string())
conf_data.set('USE_SYSTEM_CERT_PROVIDER', use_system_cert_provider.to_string())
diff --git a/src/gui/game/Tool.h b/src/gui/game/Tool.h
index 97c3c9dd9..273b347b1 100644
--- a/src/gui/game/Tool.h
+++ b/src/gui/game/Tool.h
@@ -10,7 +10,7 @@
class Simulation;
class Brush;
class VideoBuffer;
-class Particle;
+struct Particle;
class Tool
{
diff --git a/src/meson.build b/src/meson.build
index 5894519a0..1ad17e6b3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -49,6 +49,18 @@ conf_data.set('APPID', app_id)
conf_data.set('APPDATA', get_option('app_data'))
conf_data.set('APPVENDOR', get_option('app_vendor'))
+if host_platform == 'android'
+ android_permissions = [
+ '',
+ ]
+ if enable_http
+ android_permissions += [
+ '',
+ ]
+ endif
+ conf_data.set('ANDROID_PERMISSIONS', '\n'.join(android_permissions))
+endif
+
powder_files = files(
'SDLCompat.cpp',
'PowderToySDL.cpp',