diff options
Diffstat (limited to 'platform/android')
15 files changed, 495 insertions, 71 deletions
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp index 0ace7d03a1..09c981b3fa 100644 --- a/platform/android/audio_driver_jandroid.cpp +++ b/platform/android/audio_driver_jandroid.cpp @@ -73,9 +73,9 @@ Error AudioDriverAndroid::init() { // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); JNIEnv *env = ThreadAndroid::get_env(); - int mix_rate = GLOBAL_DEF_RST("audio/mix_rate", 44100); + int mix_rate = GLOBAL_GET("audio/mix_rate"); - int latency = GLOBAL_DEF_RST("audio/output_latency", 25); + int latency = GLOBAL_GET("audio/output_latency"); unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000); print_verbose("Audio buffer size: " + itos(buffer_size)); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 0b6c6990f3..dfaaf68b69 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -44,6 +44,7 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "platform/android/logo.gen.h" +#include "platform/android/plugin/godot_plugin_config.h" #include "platform/android/run_icon.gen.h" #include <string.h> @@ -252,16 +253,45 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { EditorProgress *ep; }; + Vector<PluginConfig> plugins; + volatile bool plugins_changed; + Mutex plugins_lock; Vector<Device> devices; volatile bool devices_changed; Mutex device_lock; - Thread *device_thread; + Thread *check_for_changes_thread; volatile bool quit_request; - static void _device_poll_thread(void *ud) { + static void _check_for_changes_poll_thread(void *ud) { EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; while (!ea->quit_request) { + // Check for plugins updates + { + // Nothing to do if we already know the plugins have changed. + if (!ea->plugins_changed) { + Vector<PluginConfig> loaded_plugins = get_plugins(); + + MutexLock lock(ea->plugins_lock); + + if (ea->plugins.size() != loaded_plugins.size()) { + ea->plugins_changed = true; + } else { + for (int i = 0; i < ea->plugins.size(); i++) { + if (ea->plugins[i].name != loaded_plugins[i].name) { + ea->plugins_changed = true; + break; + } + } + } + + if (ea->plugins_changed) { + ea->plugins = loaded_plugins; + } + } + } + + // Check for devices updates String adb = EditorSettings::get_singleton()->get("export/android/adb"); if (FileAccess::exists(adb)) { String devices; @@ -573,6 +603,73 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { return abis; } + /// List the gdap files in the directory specified by the p_path parameter. + static Vector<String> list_gdap_files(const String &p_path) { + Vector<String> dir_files; + DirAccessRef da = DirAccess::open(p_path); + if (da) { + da->list_dir_begin(); + while (true) { + String file = da->get_next(); + if (file == "") { + break; + } + + if (da->current_is_dir() || da->current_is_hidden()) { + continue; + } + + if (file.ends_with(PLUGIN_CONFIG_EXT)) { + dir_files.push_back(file); + } + } + da->list_dir_end(); + } + + return dir_files; + } + + static Vector<PluginConfig> get_plugins() { + Vector<PluginConfig> loaded_plugins; + + String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins"); + + // Add the prebuilt plugins + loaded_plugins.append_array(get_prebuilt_plugins(plugins_dir)); + + if (DirAccess::exists(plugins_dir)) { + Vector<String> plugins_filenames = list_gdap_files(plugins_dir); + + if (!plugins_filenames.empty()) { + Ref<ConfigFile> config_file = memnew(ConfigFile); + for (int i = 0; i < plugins_filenames.size(); i++) { + PluginConfig config = load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i])); + if (config.valid_config) { + loaded_plugins.push_back(config); + } else { + print_error("Invalid plugin config file " + plugins_filenames[i]); + } + } + } + } + + return loaded_plugins; + } + + static Vector<PluginConfig> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets) { + Vector<PluginConfig> enabled_plugins; + Vector<PluginConfig> all_plugins = get_plugins(); + for (int i = 0; i < all_plugins.size(); i++) { + PluginConfig plugin = all_plugins[i]; + bool enabled = p_presets->get("plugins/" + plugin.name); + if (enabled) { + enabled_plugins.push_back(plugin); + } + } + + return enabled_plugins; + } + static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED) { zip_fileinfo zipfi = get_zip_fileinfo(); zipOpenNewFileInZip(ed->apk, @@ -674,7 +771,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { int xr_mode_index = p_preset->get("xr_features/xr_mode"); - String plugins = p_preset->get("custom_template/plugins"); + String plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); Vector<String> perms; @@ -829,9 +926,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } } - if (tname == "meta-data" && attrname == "value" && value == "custom_template_plugins_value") { + if (tname == "meta-data" && attrname == "value" && value == "plugins_value" && !plugins_names.empty()) { // Update the meta-data 'android:value' attribute with the list of enabled plugins. - string_table.write[attr_value] = plugins; + string_table.write[attr_value] = plugins_names; } iofs += 20; @@ -865,8 +962,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { feature_required_list.push_back(hand_tracking_index == 2); feature_versions.push_back(-1); // no version attribute should be added. - if (perms.find("oculus.permission.handtracking") == -1) { - perms.push_back("oculus.permission.handtracking"); + if (perms.find("com.oculus.permission.HAND_TRACKING") == -1) { + perms.push_back("com.oculus.permission.HAND_TRACKING"); } } } @@ -1354,7 +1451,14 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/plugins", PROPERTY_HINT_PLACEHOLDER_TEXT, "Plugin1,Plugin2,..."), "")); + + Vector<PluginConfig> plugins_configs = get_plugins(); + for (int i = 0; i < plugins_configs.size(); i++) { + print_verbose("Found Android plugin " + plugins_configs[i].name); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false)); + } + plugins_changed = false; + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); @@ -1409,6 +1513,15 @@ public: return logo; } + virtual bool should_update_export_options() { + bool export_options_changed = plugins_changed; + if (export_options_changed) { + // don't clear unless we're reporting true, to avoid race + plugins_changed = false; + } + return export_options_changed; + } + virtual bool poll_export() { bool dc = devices_changed; if (dc) { @@ -1755,18 +1868,22 @@ public: #endif String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build"); - String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins"); build_command = build_path.plus_file(build_command); String package_name = get_package_name(p_preset->get("package/unique_name")); - String plugins = p_preset->get("custom_template/plugins"); + + Vector<PluginConfig> enabled_plugins = get_enabled_plugins(p_preset); + String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins); + String remote_plugins_binaries = get_plugins_binaries(BINARY_TYPE_REMOTE, enabled_plugins); + String custom_maven_repos = get_plugins_custom_maven_repos(enabled_plugins); List<String> cmdline; cmdline.push_back("build"); cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name. - cmdline.push_back("-Pcustom_template_plugins_dir=" + plugins_dir); // argument to specify the plugins directory. - cmdline.push_back("-Pcustom_template_plugins=" + plugins); // argument to specify the list of plugins to enable. + cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies. + cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies. + cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies. cmdline.push_back("-p"); // argument to specify the start directory. cmdline.push_back(build_path); // start directory. /*{ used for debug @@ -2283,14 +2400,15 @@ public: run_icon->create_from_image(img); devices_changed = true; + plugins_changed = true; quit_request = false; - device_thread = Thread::create(_device_poll_thread, this); + check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this); } ~EditorExportPlatformAndroid() { quit_request = true; - Thread::wait_to_finish(device_thread); - memdelete(device_thread); + Thread::wait_to_finish(check_for_changes_thread); + memdelete(check_for_changes_thread); } }; diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index cc480d1c84..f5b1d29f22 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -32,8 +32,8 @@ <!-- Metadata populated at export time and used by Godot to figure out which plugins must be enabled. --> <meta-data - android:name="custom_template_plugins" - android:value="custom_template_plugins_value"/> + android:name="plugins" + android:value="plugins_value"/> <activity android:name=".GodotApp" diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 9ae47d6174..ea341b37b1 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -21,6 +21,16 @@ allprojects { mavenCentral() google() jcenter() + + // Godot user plugins custom maven repos + String[] mavenRepos = getGodotPluginsMavenRepos() + if (mavenRepos != null && mavenRepos.size() > 0) { + for (String repoUrl : mavenRepos) { + maven { + url repoUrl + } + } + } } } @@ -40,15 +50,18 @@ dependencies { releaseImplementation fileTree(dir: 'libs/release', include: ['*.jar', '*.aar']) } - // Godot prebuilt plugins - implementation fileTree(dir: 'libs/plugins', include: ["GodotPayment*.aar"]) + // Godot user plugins remote dependencies + String[] remoteDeps = getGodotPluginsRemoteBinaries() + if (remoteDeps != null && remoteDeps.size() > 0) { + for (String dep : remoteDeps) { + implementation dep + } + } - // Godot user plugins dependencies - String pluginsDir = getGodotPluginsDirectory() - String[] pluginsBinaries = getGodotPluginsBinaries() - if (pluginsDir != null && !pluginsDir.isEmpty() && - pluginsBinaries != null && pluginsBinaries.size() > 0) { - implementation fileTree(dir: pluginsDir, include: pluginsBinaries) + // Godot user plugins local dependencies + String[] pluginsBinaries = getGodotPluginsLocalBinaries() + if (pluginsBinaries != null && pluginsBinaries.size() > 0) { + implementation files(pluginsBinaries) } } diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index aa98194a10..5251bc3066 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -4,18 +4,18 @@ ext.versions = [ minSdk : 18, targetSdk : 29, buildTools : '29.0.3', - supportCoreUtils : '28.0.0', + supportCoreUtils : '1.0.0', kotlinVersion : '1.3.61', - v4Support : '28.0.0' + v4Support : '1.0.0' ] ext.libraries = [ androidGradlePlugin: "com.android.tools.build:gradle:$versions.androidGradlePlugin", - supportCoreUtils : "com.android.support:support-core-utils:$versions.supportCoreUtils", + supportCoreUtils : "androidx.legacy:legacy-support-core-utils:$versions.supportCoreUtils", kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlinVersion", kotlinStdLib : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlinVersion", - v4Support : "com.android.support:support-v4:$versions.v4Support" + v4Support : "androidx.legacy:legacy-support-v4:$versions.v4Support" ] ext.getExportPackageName = { -> @@ -28,39 +28,68 @@ ext.getExportPackageName = { -> return appId } +final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|" + /** - * Parse the project properties for the 'custom_template_plugins' property and return - * their binaries for inclusion in the build dependencies. - * - * The listed plugins must have their binaries in the project plugins directory. + * Parse the project properties for the 'plugins_maven_repos' property and return the list + * of maven repos. */ -ext.getGodotPluginsBinaries = { -> - String[] binDeps = [] +ext.getGodotPluginsMavenRepos = { -> + Set<String> mavenRepos = [] - // Retrieve the list of enabled plugins. - if (project.hasProperty("custom_template_plugins")) { - String pluginsList = project.property("custom_template_plugins") - if (pluginsList != null && !pluginsList.trim().isEmpty()) { - for (String plugin : pluginsList.split(",")) { - binDeps += plugin.trim() + "*.aar" + // Retrieve the list of maven repos. + if (project.hasProperty("plugins_maven_repos")) { + String mavenReposProperty = project.property("plugins_maven_repos") + if (mavenReposProperty != null && !mavenReposProperty.trim().isEmpty()) { + for (String mavenRepoUrl : mavenReposProperty.split(PLUGIN_VALUE_SEPARATOR_REGEX)) { + mavenRepos += mavenRepoUrl.trim() } } } - return binDeps + return mavenRepos +} + +/** + * Parse the project properties for the 'plugins_remote_binaries' property and return + * it for inclusion in the build dependencies. + */ +ext.getGodotPluginsRemoteBinaries = { -> + Set<String> remoteDeps = [] + + // Retrieve the list of remote plugins binaries. + if (project.hasProperty("plugins_remote_binaries")) { + String remoteDepsList = project.property("plugins_remote_binaries") + if (remoteDepsList != null && !remoteDepsList.trim().isEmpty()) { + for (String dep: remoteDepsList.split(PLUGIN_VALUE_SEPARATOR_REGEX)) { + remoteDeps += dep.trim() + } + } + } + return remoteDeps } /** - * Parse the project properties for the 'custom_template_plugins_dir' property and return - * its value. + * Parse the project properties for the 'plugins_local_binaries' property and return + * their binaries for inclusion in the build dependencies. * - * The returned value is the directory containing user plugins. + * Returns the prebuilt plugins if the 'plugins_local_binaries' property is unavailable. */ -ext.getGodotPluginsDirectory = { -> - // The plugins directory is provided by the 'custom_template_plugins_dir' property. - String pluginsDir = project.hasProperty("custom_template_plugins_dir") - ? project.property("custom_template_plugins_dir") - : "" +ext.getGodotPluginsLocalBinaries = { -> + // Set the prebuilt plugins as default. If custom build is enabled, + // the 'plugins_local_binaries' will be defined so we can use it instead. + Set<String> binDeps = ["libs/plugins/GodotPayment.release.aar"] + + // Retrieve the list of local plugins binaries. + if (project.hasProperty("plugins_local_binaries")) { + binDeps.clear() + String pluginsList = project.property("plugins_local_binaries") + if (pluginsList != null && !pluginsList.trim().isEmpty()) { + for (String plugin : pluginsList.split(PLUGIN_VALUE_SEPARATOR_REGEX)) { + binDeps += plugin.trim() + } + } + } - return pluginsDir + return binDeps } diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index 865b61956c..01a3607b20 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -140,7 +140,7 @@ task generateGodotTemplates(type: GradleBuild) { startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType) } - tasks = ["copyGodotPaymentPluginToAppModule"] + tasks = [] // Only build the apks and aar files for which we have native shared libraries. for (String target : supportedTargets) { @@ -161,6 +161,7 @@ task generateGodotTemplates(type: GradleBuild) { } } + dependsOn 'copyGodotPaymentPluginToAppModule' finalizedBy 'zipCustomBuild' } diff --git a/platform/android/java/gradle.properties b/platform/android/java/gradle.properties index aac7c9b461..e14cd5ba5c 100644 --- a/platform/android/java/gradle.properties +++ b/platform/android/java/gradle.properties @@ -7,6 +7,9 @@ # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html +android.enableJetifier=true +android.useAndroidX=true + # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m diff --git a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java index 0abaf2e052..d481c22204 100644 --- a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java +++ b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java @@ -29,9 +29,9 @@ import com.google.android.vending.expansion.downloader.IDownloaderClient; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; -import android.os.Build; import android.os.Messenger; -import android.support.v4.app.NotificationCompat; + +import androidx.core.app.NotificationCompat; /** * This class handles displaying the notification associated with the download diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index cc9c7a9652..f27d8620ec 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -66,10 +66,6 @@ import android.os.Messenger; import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings.Secure; -import android.support.annotation.CallSuper; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.v4.app.FragmentActivity; import android.view.Display; import android.view.KeyEvent; import android.view.MotionEvent; @@ -85,6 +81,11 @@ import android.widget.FrameLayout; import android.widget.ProgressBar; import android.widget.TextView; +import androidx.annotation.CallSuper; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; + import com.google.android.vending.expansion.downloader.DownloadProgressInfo; import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller; import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller; diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java index a8146a1332..431bd4f5f9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java @@ -35,13 +35,13 @@ import org.godotengine.godot.Godot; import android.app.Activity; import android.content.Intent; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; import android.util.Log; import android.view.Surface; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java index bb11300861..12d2ed09fb 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java @@ -35,13 +35,13 @@ import org.godotengine.godot.Godot; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; -import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.Nullable; + import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -58,7 +58,9 @@ public final class GodotPluginRegistry { /** * Name for the metadata containing the list of Godot plugins to enable. */ - private static final String GODOT_ENABLED_PLUGINS_LABEL = "custom_template_plugins"; + private static final String GODOT_ENABLED_PLUGINS_LABEL = "plugins"; + + private static final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|"; private static GodotPluginRegistry instance; private final ConcurrentHashMap<String, GodotPlugin> registry; @@ -128,13 +130,13 @@ public final class GodotPluginRegistry { } // When using the Godot editor for building and exporting the apk, this is used to check - // which plugins to enable since the custom build template may contain prebuilt plugins. + // which plugins to enable. // When using a custom process to generate the apk, the metadata is not needed since // it's assumed that the developer is aware of the dependencies included in the apk. final Set<String> enabledPluginsSet; if (metaData.containsKey(GODOT_ENABLED_PLUGINS_LABEL)) { String enabledPlugins = metaData.getString(GODOT_ENABLED_PLUGINS_LABEL, ""); - String[] enabledPluginsList = enabledPlugins.split(","); + String[] enabledPluginsList = enabledPlugins.split(PLUGIN_VALUE_SEPARATOR_REGEX); if (enabledPluginsList.length == 0) { // No plugins to enable. Aborting early. return; @@ -158,6 +160,8 @@ public final class GodotPluginRegistry { continue; } + Log.i(TAG, "Initializing Godot plugin " + pluginName); + // Retrieve the plugin class full name. String pluginHandleClassFullName = metaData.getString(metaDataName); if (!TextUtils.isEmpty(pluginHandleClassFullName)) { @@ -177,6 +181,7 @@ public final class GodotPluginRegistry { "Meta-data plugin name does not match the value returned by the plugin handle: " + pluginName + " =/= " + pluginHandle.getPluginName()); } registry.put(pluginName, pluginHandle); + Log.i(TAG, "Completed initialization for Godot plugin " + pluginHandle.getPluginName()); } catch (ClassNotFoundException e) { Log.w(TAG, "Unable to load Godot plugin " + pluginName, e); } catch (IllegalAccessException e) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java index 71523d8c27..f82c4d3fa0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java @@ -30,9 +30,10 @@ package org.godotengine.godot.plugin; -import android.support.annotation.NonNull; import android.text.TextUtils; +import androidx.annotation.NonNull; + import java.util.Arrays; /** diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java index c34e4c18db..6837e4f147 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java @@ -37,9 +37,10 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Build; -import android.support.v4.content.ContextCompat; import android.util.Log; +import androidx.core.content.ContextCompat; + import java.util.ArrayList; import java.util.List; diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java index 6f76007e1e..ded7f0a9aa 100644 --- a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java +++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java @@ -36,9 +36,10 @@ import org.godotengine.godot.GodotLib; import org.godotengine.godot.plugin.GodotPlugin; import android.content.Intent; -import android.support.annotation.NonNull; import android.util.Log; +import androidx.annotation.NonNull; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/platform/android/plugin/godot_plugin_config.h b/platform/android/plugin/godot_plugin_config.h new file mode 100644 index 0000000000..9ad7de1202 --- /dev/null +++ b/platform/android/plugin/godot_plugin_config.h @@ -0,0 +1,251 @@ +/*************************************************************************/ +/* godot_plugin_config.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_PLUGIN_CONFIG_H +#define GODOT_PLUGIN_CONFIG_H + +#include "core/error_list.h" +#include "core/io/config_file.h" +#include "core/ustring.h" + +static const char *PLUGIN_CONFIG_EXT = ".gdap"; + +static const char *CONFIG_SECTION = "config"; +static const char *CONFIG_NAME_KEY = "name"; +static const char *CONFIG_BINARY_TYPE_KEY = "binary_type"; +static const char *CONFIG_BINARY_KEY = "binary"; + +static const char *DEPENDENCIES_SECTION = "dependencies"; +static const char *DEPENDENCIES_LOCAL_KEY = "local"; +static const char *DEPENDENCIES_REMOTE_KEY = "remote"; +static const char *DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY = "custom_maven_repos"; + +static const char *BINARY_TYPE_LOCAL = "local"; +static const char *BINARY_TYPE_REMOTE = "remote"; + +static const char *PLUGIN_VALUE_SEPARATOR = "|"; + +/* + The `config` section and fields are required and defined as follow: +- **name**: name of the plugin +- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field +- **binary**: + - if **binary_type** is `local`, then this should be the filename of the plugin `aar` file in the `res://android/plugins` directory (e.g: `MyPlugin.aar`). + - if **binary_type** is `remote`, then this should be a declaration for a remote gradle binary (e.g: "org.godot.example:my-plugin:0.0.0"). + +The `dependencies` section and fields are optional and defined as follow: +- **local**: contains a list of local `.aar` binary files the plugin depends on. The local binary dependencies must also be located in the `res://android/plugins` directory. +- **remote**: contains a list of remote binary gradle dependencies for the plugin. +- **custom_maven_repos**: contains a list of urls specifying custom maven repos required for the plugin's dependencies. + + See https://github.com/godotengine/godot/issues/38157#issuecomment-618773871 + */ +struct PluginConfig { + // Set to true when the config file is properly loaded. + bool valid_config = false; + + // Required config section + String name; + String binary_type; + String binary; + + // Optional dependencies section + Vector<String> local_dependencies; + Vector<String> remote_dependencies; + Vector<String> custom_maven_repos; +}; + +/* + * Set of prebuilt plugins. + */ +static const PluginConfig GODOT_PAYMENT = { + /*.valid_config =*/true, + /*.name =*/"GodotPayment", + /*.binary_type =*/"local", + /*.binary =*/"res://android/build/libs/plugins/GodotPayment.release.aar", + /*.local_dependencies =*/{}, + /*.remote_dependencies =*/{}, + /*.custom_maven_repos =*/{} +}; + +static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) { + String absolute_path; + if (!dependency_path.empty()) { + if (dependency_path.is_abs_path()) { + absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path); + } else { + absolute_path = plugin_config_dir.plus_file(dependency_path); + } + } + + return absolute_path; +} + +static inline PluginConfig resolve_prebuilt_plugin(PluginConfig prebuilt_plugin, String plugin_config_dir) { + PluginConfig resolved = prebuilt_plugin; + resolved.binary = resolved.binary_type == BINARY_TYPE_LOCAL ? resolve_local_dependency_path(plugin_config_dir, prebuilt_plugin.binary) : prebuilt_plugin.binary; + if (!prebuilt_plugin.local_dependencies.empty()) { + resolved.local_dependencies.clear(); + for (int i = 0; i < prebuilt_plugin.local_dependencies.size(); i++) { + resolved.local_dependencies.push_back(resolve_local_dependency_path(plugin_config_dir, prebuilt_plugin.local_dependencies[i])); + } + } + return resolved; +} + +static inline Vector<PluginConfig> get_prebuilt_plugins(String plugins_base_dir) { + Vector<PluginConfig> prebuilt_plugins; + prebuilt_plugins.push_back(resolve_prebuilt_plugin(GODOT_PAYMENT, plugins_base_dir)); + return prebuilt_plugins; +} + +static inline bool is_plugin_config_valid(PluginConfig plugin_config) { + bool valid_name = !plugin_config.name.empty(); + bool valid_binary_type = plugin_config.binary_type == BINARY_TYPE_LOCAL || + plugin_config.binary_type == BINARY_TYPE_REMOTE; + + bool valid_binary = false; + if (valid_binary_type) { + valid_binary = !plugin_config.binary.empty() && + (plugin_config.binary_type == BINARY_TYPE_REMOTE || + FileAccess::exists(plugin_config.binary)); + } + + bool valid_local_dependencies = true; + if (!plugin_config.local_dependencies.empty()) { + for (int i = 0; i < plugin_config.local_dependencies.size(); i++) { + if (!FileAccess::exists(plugin_config.local_dependencies[i])) { + valid_local_dependencies = false; + break; + } + } + } + return valid_name && valid_binary && valid_binary_type && valid_local_dependencies; +} + +static inline PluginConfig load_plugin_config(Ref<ConfigFile> config_file, const String &path) { + PluginConfig plugin_config = {}; + + if (config_file.is_valid()) { + Error err = config_file->load(path); + if (err == OK) { + String config_base_dir = path.get_base_dir(); + + plugin_config.name = config_file->get_value(CONFIG_SECTION, CONFIG_NAME_KEY, String()); + plugin_config.binary_type = config_file->get_value(CONFIG_SECTION, CONFIG_BINARY_TYPE_KEY, String()); + + String binary_path = config_file->get_value(CONFIG_SECTION, CONFIG_BINARY_KEY, String()); + plugin_config.binary = plugin_config.binary_type == BINARY_TYPE_LOCAL ? resolve_local_dependency_path(config_base_dir, binary_path) : binary_path; + + if (config_file->has_section(DEPENDENCIES_SECTION)) { + Vector<String> local_dependencies_paths = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_LOCAL_KEY, Vector<String>()); + if (!local_dependencies_paths.empty()) { + for (int i = 0; i < local_dependencies_paths.size(); i++) { + plugin_config.local_dependencies.push_back(resolve_local_dependency_path(config_base_dir, local_dependencies_paths[i])); + } + } + + plugin_config.remote_dependencies = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_REMOTE_KEY, Vector<String>()); + plugin_config.custom_maven_repos = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY, Vector<String>()); + } + + plugin_config.valid_config = is_plugin_config_valid(plugin_config); + } + } + + return plugin_config; +} + +static inline String get_plugins_binaries(String binary_type, Vector<PluginConfig> plugins_configs) { + String plugins_binaries; + if (!plugins_configs.empty()) { + Vector<String> binaries; + for (int i = 0; i < plugins_configs.size(); i++) { + PluginConfig config = plugins_configs[i]; + if (!config.valid_config) { + continue; + } + + if (config.binary_type == binary_type) { + binaries.push_back(config.binary); + } + + if (binary_type == BINARY_TYPE_LOCAL) { + binaries.append_array(config.local_dependencies); + } + + if (binary_type == BINARY_TYPE_REMOTE) { + binaries.append_array(config.remote_dependencies); + } + } + + plugins_binaries = String(PLUGIN_VALUE_SEPARATOR).join(binaries); + } + + return plugins_binaries; +} + +static inline String get_plugins_custom_maven_repos(Vector<PluginConfig> plugins_configs) { + String custom_maven_repos; + if (!plugins_configs.empty()) { + Vector<String> repos_urls; + for (int i = 0; i < plugins_configs.size(); i++) { + PluginConfig config = plugins_configs[i]; + if (!config.valid_config) { + continue; + } + + repos_urls.append_array(config.custom_maven_repos); + } + + custom_maven_repos = String(PLUGIN_VALUE_SEPARATOR).join(repos_urls); + } + return custom_maven_repos; +} + +static inline String get_plugins_names(Vector<PluginConfig> plugins_configs) { + String plugins_names; + if (!plugins_configs.empty()) { + Vector<String> names; + for (int i = 0; i < plugins_configs.size(); i++) { + PluginConfig config = plugins_configs[i]; + if (!config.valid_config) { + continue; + } + + names.push_back(config.name); + } + plugins_names = String(PLUGIN_VALUE_SEPARATOR).join(names); + } + + return plugins_names; +} + +#endif // GODOT_PLUGIN_CONFIG_H |