mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Bump the minimum supported SDK version to 24
Raise the minimum supported Android version from Android 5 (Lollipop) to Android 7 (Nougat).
This commit is contained in:
parent
8f78e7510d
commit
c29545f793
15 changed files with 96 additions and 180 deletions
|
@ -73,7 +73,7 @@ def get_ndk_version():
|
||||||
|
|
||||||
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
|
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
|
||||||
def get_min_target_api():
|
def get_min_target_api():
|
||||||
return 21
|
return 24
|
||||||
|
|
||||||
|
|
||||||
def get_flags():
|
def get_flags():
|
||||||
|
|
|
@ -281,8 +281,7 @@ static const int EXPORT_FORMAT_AAB = 1;
|
||||||
static const char *APK_ASSETS_DIRECTORY = "assets";
|
static const char *APK_ASSETS_DIRECTORY = "assets";
|
||||||
static const char *AAB_ASSETS_DIRECTORY = "assetPacks/installTime/src/main/assets";
|
static const char *AAB_ASSETS_DIRECTORY = "assetPacks/installTime/src/main/assets";
|
||||||
|
|
||||||
static const int OPENGL_MIN_SDK_VERSION = 21; // Should match the value in 'platform/android/java/app/config.gradle#minSdk'
|
static const int DEFAULT_MIN_SDK_VERSION = 24; // Should match the value in 'platform/android/java/app/config.gradle#minSdk'
|
||||||
static const int VULKAN_MIN_SDK_VERSION = 24;
|
|
||||||
static const int DEFAULT_TARGET_SDK_VERSION = 35; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk'
|
static const int DEFAULT_TARGET_SDK_VERSION = 35; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk'
|
||||||
|
|
||||||
#ifndef ANDROID_ENABLED
|
#ifndef ANDROID_ENABLED
|
||||||
|
@ -1963,7 +1962,6 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
|
||||||
}
|
}
|
||||||
} else if (p_name == "gradle_build/min_sdk") {
|
} else if (p_name == "gradle_build/min_sdk") {
|
||||||
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
|
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
|
||||||
int min_sdk_int = VULKAN_MIN_SDK_VERSION;
|
|
||||||
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
|
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
|
||||||
if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do.
|
if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do.
|
||||||
if (!gradle_build_enabled) {
|
if (!gradle_build_enabled) {
|
||||||
|
@ -1972,9 +1970,9 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
|
||||||
if (!min_sdk_str.is_valid_int()) {
|
if (!min_sdk_str.is_valid_int()) {
|
||||||
return vformat(TTR("\"Min SDK\" should be a valid integer, but got \"%s\" which is invalid."), min_sdk_str);
|
return vformat(TTR("\"Min SDK\" should be a valid integer, but got \"%s\" which is invalid."), min_sdk_str);
|
||||||
} else {
|
} else {
|
||||||
min_sdk_int = min_sdk_str.to_int();
|
int min_sdk_int = min_sdk_str.to_int();
|
||||||
if (min_sdk_int < OPENGL_MIN_SDK_VERSION) {
|
if (min_sdk_int < DEFAULT_MIN_SDK_VERSION) {
|
||||||
return vformat(TTR("\"Min SDK\" cannot be lower than %d, which is the version needed by the Godot library."), OPENGL_MIN_SDK_VERSION);
|
return vformat(TTR("\"Min SDK\" cannot be lower than %d, which is the version needed by the Godot library."), DEFAULT_MIN_SDK_VERSION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1983,7 +1981,7 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
|
||||||
int target_sdk_int = DEFAULT_TARGET_SDK_VERSION;
|
int target_sdk_int = DEFAULT_TARGET_SDK_VERSION;
|
||||||
|
|
||||||
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
|
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
|
||||||
int min_sdk_int = VULKAN_MIN_SDK_VERSION;
|
int min_sdk_int = DEFAULT_MIN_SDK_VERSION;
|
||||||
if (min_sdk_str.is_valid_int()) {
|
if (min_sdk_str.is_valid_int()) {
|
||||||
min_sdk_int = min_sdk_str.to_int();
|
min_sdk_int = min_sdk_str.to_int();
|
||||||
}
|
}
|
||||||
|
@ -2032,7 +2030,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "gradle_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK, false, true));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "gradle_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK, false, true));
|
||||||
// Using String instead of int to default to an empty string (no override) with placeholder for instructions (see GH-62465).
|
// Using String instead of int to default to an empty string (no override) with placeholder for instructions (see GH-62465).
|
||||||
// This implies doing validation that the string is a proper int.
|
// This implies doing validation that the string is a proper int.
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", VULKAN_MIN_SDK_VERSION)), "", false, true));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_MIN_SDK_VERSION)), "", false, true));
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "", false, true));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "", false, true));
|
||||||
|
|
||||||
#ifndef DISABLE_DEPRECATED
|
#ifndef DISABLE_DEPRECATED
|
||||||
|
@ -2903,14 +2901,6 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
|
|
||||||
int min_sdk_int = VULKAN_MIN_SDK_VERSION;
|
|
||||||
if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do.
|
|
||||||
if (min_sdk_str.is_valid_int()) {
|
|
||||||
min_sdk_int = min_sdk_str.to_int();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String target_sdk_str = p_preset->get("gradle_build/target_sdk");
|
String target_sdk_str = p_preset->get("gradle_build/target_sdk");
|
||||||
int target_sdk_int = DEFAULT_TARGET_SDK_VERSION;
|
int target_sdk_int = DEFAULT_TARGET_SDK_VERSION;
|
||||||
if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do.
|
if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do.
|
||||||
|
@ -2931,12 +2921,6 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit
|
||||||
err += "\n";
|
err += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_uses_vulkan(p_preset) && min_sdk_int < VULKAN_MIN_SDK_VERSION) {
|
|
||||||
// Warning only, so don't override `valid`.
|
|
||||||
err += vformat(TTR("\"Min SDK\" should be greater or equal to %d for the \"%s\" renderer."), VULKAN_MIN_SDK_VERSION, current_renderer);
|
|
||||||
err += "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
String package_name = p_preset->get("package/unique_name");
|
String package_name = p_preset->get("package/unique_name");
|
||||||
if (package_name.contains("$genname") && !is_project_name_valid(p_preset)) {
|
if (package_name.contains("$genname") && !is_project_name_valid(p_preset)) {
|
||||||
// Warning only, so don't override `valid`.
|
// Warning only, so don't override `valid`.
|
||||||
|
@ -3507,7 +3491,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
String version_name = p_preset->get_version("version/name");
|
String version_name = p_preset->get_version("version/name");
|
||||||
String min_sdk_version = p_preset->get("gradle_build/min_sdk");
|
String min_sdk_version = p_preset->get("gradle_build/min_sdk");
|
||||||
if (!min_sdk_version.is_valid_int()) {
|
if (!min_sdk_version.is_valid_int()) {
|
||||||
min_sdk_version = itos(VULKAN_MIN_SDK_VERSION);
|
min_sdk_version = itos(DEFAULT_MIN_SDK_VERSION);
|
||||||
}
|
}
|
||||||
String target_sdk_version = p_preset->get("gradle_build/target_sdk");
|
String target_sdk_version = p_preset->get("gradle_build/target_sdk");
|
||||||
if (!target_sdk_version.is_valid_int()) {
|
if (!target_sdk_version.is_valid_int()) {
|
||||||
|
@ -3947,6 +3931,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
|
|
||||||
// Let's zip-align (must be done before signing)
|
// Let's zip-align (must be done before signing)
|
||||||
|
|
||||||
|
static const int PAGE_SIZE_KB = 16 * 1024;
|
||||||
static const int ZIP_ALIGNMENT = 4;
|
static const int ZIP_ALIGNMENT = 4;
|
||||||
|
|
||||||
// If we're not signing the apk, then the next step should be the last.
|
// If we're not signing the apk, then the next step should be the last.
|
||||||
|
@ -3998,7 +3983,12 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
if (!info.compression_method) {
|
if (!info.compression_method) {
|
||||||
// Uncompressed file => Align
|
// Uncompressed file => Align
|
||||||
long new_offset = file_offset + bias;
|
long new_offset = file_offset + bias;
|
||||||
padding = (ZIP_ALIGNMENT - (new_offset % ZIP_ALIGNMENT)) % ZIP_ALIGNMENT;
|
const char *ext = strrchr(fname, '.');
|
||||||
|
if (ext && strcmp(ext, ".so") == 0) {
|
||||||
|
padding = (PAGE_SIZE_KB - (new_offset % PAGE_SIZE_KB)) % PAGE_SIZE_KB;
|
||||||
|
} else {
|
||||||
|
padding = (ZIP_ALIGNMENT - (new_offset % ZIP_ALIGNMENT)) % ZIP_ALIGNMENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(extra + info.size_file_extra, 0, padding);
|
memset(extra + info.size_file_extra, 0, padding);
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
ext.versions = [
|
ext.versions = [
|
||||||
androidGradlePlugin: '8.6.1',
|
androidGradlePlugin: '8.6.1',
|
||||||
compileSdk : 35,
|
compileSdk : 35,
|
||||||
// Also update 'platform/android/export/export_plugin.cpp#OPENGL_MIN_SDK_VERSION'
|
// Also update:
|
||||||
minSdk : 21,
|
// - 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION'
|
||||||
|
// - 'platform/android/detect.py#get_min_target_api()'
|
||||||
|
minSdk : 24,
|
||||||
// Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
|
// Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
|
||||||
targetSdk : 35,
|
targetSdk : 35,
|
||||||
buildTools : '35.0.0',
|
buildTools : '35.0.0',
|
||||||
|
@ -382,17 +384,12 @@ ext.shouldNotStrip = { ->
|
||||||
*/
|
*/
|
||||||
ext.shouldUseLegacyPackaging = { ->
|
ext.shouldUseLegacyPackaging = { ->
|
||||||
int minSdk = getExportMinSdkVersion()
|
int minSdk = getExportMinSdkVersion()
|
||||||
if (minSdk < 23) {
|
|
||||||
// Enforce the default behavior for compatibility with device running api < 23
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
String legacyPackagingFlag = project.hasProperty("compress_native_libraries") ? project.property("compress_native_libraries") : ""
|
String legacyPackagingFlag = project.hasProperty("compress_native_libraries") ? project.property("compress_native_libraries") : ""
|
||||||
if (legacyPackagingFlag != null && !legacyPackagingFlag.isEmpty()) {
|
if (legacyPackagingFlag != null && !legacyPackagingFlag.isEmpty()) {
|
||||||
return Boolean.parseBoolean(legacyPackagingFlag)
|
return Boolean.parseBoolean(legacyPackagingFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default behavior for minSdk >= 23
|
// Default behavior for minSdk >= 24
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,6 @@ android {
|
||||||
}
|
}
|
||||||
applicationIdSuffix ".meta"
|
applicationIdSuffix ".meta"
|
||||||
versionNameSuffix "-meta"
|
versionNameSuffix "-meta"
|
||||||
minSdkVersion 23
|
|
||||||
targetSdkVersion 32
|
targetSdkVersion 32
|
||||||
}
|
}
|
||||||
picoos {
|
picoos {
|
||||||
|
|
|
@ -192,13 +192,11 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||||
Manifest.permission.RECORD_AUDIO,
|
Manifest.permission.RECORD_AUDIO,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
excludedPermissions.add(
|
||||||
excludedPermissions.add(
|
// The REQUEST_INSTALL_PACKAGES permission is requested the first time we attempt to
|
||||||
// The REQUEST_INSTALL_PACKAGES permission is requested the first time we attempt to
|
// open an apk file.
|
||||||
// open an apk file.
|
Manifest.permission.REQUEST_INSTALL_PACKAGES,
|
||||||
Manifest.permission.REQUEST_INSTALL_PACKAGES,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// XR runtime permissions should only be requested when the "xr/openxr/enabled" project setting
|
// XR runtime permissions should only be requested when the "xr/openxr/enabled" project setting
|
||||||
// is enabled.
|
// is enabled.
|
||||||
|
@ -384,10 +382,8 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||||
|
|
||||||
val launchPolicy = resolveLaunchPolicyIfNeeded(editorWindowInfo.launchPolicy)
|
val launchPolicy = resolveLaunchPolicyIfNeeded(editorWindowInfo.launchPolicy)
|
||||||
if (launchPolicy == LaunchPolicy.ADJACENT) {
|
if (launchPolicy == LaunchPolicy.ADJACENT) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
Log.v(TAG, "Adding flag for adjacent launch")
|
||||||
Log.v(TAG, "Adding flag for adjacent launch")
|
newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
|
||||||
newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return newInstance
|
return newInstance
|
||||||
}
|
}
|
||||||
|
@ -511,12 +507,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||||
private fun resolveGameEmbedModeIfNeeded(embedMode: GameEmbedMode): GameEmbedMode {
|
private fun resolveGameEmbedModeIfNeeded(embedMode: GameEmbedMode): GameEmbedMode {
|
||||||
return when (embedMode) {
|
return when (embedMode) {
|
||||||
GameEmbedMode.AUTO -> {
|
GameEmbedMode.AUTO -> {
|
||||||
val inMultiWindowMode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (isInMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
||||||
isInMultiWindowMode
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
if (inMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
|
||||||
GameEmbedMode.DISABLED
|
GameEmbedMode.DISABLED
|
||||||
} else {
|
} else {
|
||||||
GameEmbedMode.ENABLED
|
GameEmbedMode.ENABLED
|
||||||
|
@ -534,12 +525,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||||
private fun resolveLaunchPolicyIfNeeded(policy: LaunchPolicy): LaunchPolicy {
|
private fun resolveLaunchPolicyIfNeeded(policy: LaunchPolicy): LaunchPolicy {
|
||||||
return when (policy) {
|
return when (policy) {
|
||||||
LaunchPolicy.AUTO -> {
|
LaunchPolicy.AUTO -> {
|
||||||
val inMultiWindowMode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
val defaultLaunchPolicy = if (isInMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
||||||
isInMultiWindowMode
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
val defaultLaunchPolicy = if (inMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
|
||||||
LaunchPolicy.ADJACENT
|
LaunchPolicy.ADJACENT
|
||||||
} else {
|
} else {
|
||||||
LaunchPolicy.SAME
|
LaunchPolicy.SAME
|
||||||
|
|
|
@ -83,7 +83,7 @@ open class GodotGame : BaseGodotGame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enterPiPMode() {
|
override fun enterPiPMode() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && hasPiPSystemFeature()) {
|
if (hasPiPSystemFeature()) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val builder = PictureInPictureParams.Builder().setSourceRectHint(gameViewSourceRectHint)
|
val builder = PictureInPictureParams.Builder().setSourceRectHint(gameViewSourceRectHint)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
@ -101,8 +101,7 @@ open class GodotGame : BaseGodotGame() {
|
||||||
* Returns true the if the device supports picture-in-picture (PiP).
|
* Returns true the if the device supports picture-in-picture (PiP).
|
||||||
*/
|
*/
|
||||||
protected fun hasPiPSystemFeature(): Boolean {
|
protected fun hasPiPSystemFeature(): Boolean {
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
|
return packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
||||||
packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shouldShowGameMenuBar(): Boolean {
|
override fun shouldShowGameMenuBar(): Boolean {
|
||||||
|
@ -123,8 +122,7 @@ open class GodotGame : BaseGodotGame() {
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
|
|
||||||
val isInPiPMode = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInPictureInPictureMode
|
if (isInPictureInPictureMode && !isFinishing) {
|
||||||
if (isInPiPMode && !isFinishing) {
|
|
||||||
// We get in this state when PiP is closed, so we terminate the activity.
|
// We get in this state when PiP is closed, so we terminate the activity.
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,19 +225,12 @@ public class Helpers {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
static public String getSaveFilePath(Context c) {
|
static public String getSaveFilePath(Context c) {
|
||||||
// This technically existed since Honeycomb, but it is critical
|
// This technically existed since Honeycomb, but it is critical
|
||||||
// on KitKat and greater versions since it will create the
|
// on KitKat and greater versions since it will create the
|
||||||
// directory if needed
|
// directory if needed
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
return c.getObbDir().toString();
|
||||||
return c.getObbDir().toString();
|
}
|
||||||
} else {
|
|
||||||
File root = Environment.getExternalStorageDirectory();
|
|
||||||
String path = root.toString() + Constants.EXP_PATH + c.getPackageName();
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to ascertain the existence of a file and return true/false appropriately
|
* Helper function to ascertain the existence of a file and return true/false appropriately
|
||||||
|
@ -297,7 +290,7 @@ public class Helpers {
|
||||||
/**
|
/**
|
||||||
* Helper function to ascertain whether the application has the correct access to the OBB
|
* Helper function to ascertain whether the application has the correct access to the OBB
|
||||||
* directory to allow an OBB file to be written.
|
* directory to allow an OBB file to be written.
|
||||||
*
|
*
|
||||||
* @param c the app/activity/service context
|
* @param c the app/activity/service context
|
||||||
* @return true if the application can write an OBB file, false otherwise
|
* @return true if the application can write an OBB file, false otherwise
|
||||||
*/
|
*/
|
||||||
|
@ -317,7 +310,7 @@ public class Helpers {
|
||||||
* Converts download states that are returned by the
|
* Converts download states that are returned by the
|
||||||
* {@link IDownloaderClient#onDownloadStateChanged} callback into usable strings. This is useful
|
* {@link IDownloaderClient#onDownloadStateChanged} callback into usable strings. This is useful
|
||||||
* if using the state strings built into the library to display user messages.
|
* if using the state strings built into the library to display user messages.
|
||||||
*
|
*
|
||||||
* @param state One of the STATE_* constants from {@link IDownloaderClient}.
|
* @param state One of the STATE_* constants from {@link IDownloaderClient}.
|
||||||
* @return string resource ID for the corresponding string.
|
* @return string resource ID for the corresponding string.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -865,16 +865,13 @@ class Godot(private val context: Context) {
|
||||||
if (packageManager == null) {
|
if (packageManager == null) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
|
||||||
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
|
// Optional requirements.. log as warning if missing
|
||||||
// Optional requirements.. log as warning if missing
|
Log.w(TAG, "The vulkan hardware level does not meet the minimum requirement: 1")
|
||||||
Log.w(TAG, "The vulkan hardware level does not meet the minimum requirement: 1")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for api version 1.0
|
|
||||||
return packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x400003)
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
|
// Check for api version 1.0
|
||||||
|
return packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x400003)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setKeepScreenOn(enabled: Boolean) {
|
private fun setKeepScreenOn(enabled: Boolean) {
|
||||||
|
|
|
@ -221,14 +221,8 @@ public class GodotFragment extends Fragment implements IDownloaderClient, GodotH
|
||||||
Intent notifierIntent = new Intent(activity, activity.getClass());
|
Intent notifierIntent = new Intent(activity, activity.getClass());
|
||||||
notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
|
||||||
PendingIntent pendingIntent;
|
PendingIntent pendingIntent = PendingIntent.getActivity(activity, 0,
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||||
pendingIntent = PendingIntent.getActivity(activity, 0,
|
|
||||||
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
|
||||||
} else {
|
|
||||||
pendingIntent = PendingIntent.getActivity(activity, 0,
|
|
||||||
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
int startResult;
|
int startResult;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -90,9 +90,7 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
|
||||||
this.godot = godot;
|
this.godot = godot;
|
||||||
this.inputHandler = inputHandler;
|
this.inputHandler = inputHandler;
|
||||||
this.godotRenderer = new GodotRenderer();
|
this.godotRenderer = new GodotRenderer();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
|
||||||
setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
|
|
||||||
}
|
|
||||||
init(xrMode, false, useDebugOpengl);
|
init(xrMode, false, useDebugOpengl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,27 +197,25 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
|
||||||
@Keep
|
@Keep
|
||||||
@Override
|
@Override
|
||||||
public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) {
|
public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) {
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
try {
|
||||||
try {
|
Bitmap bitmap = null;
|
||||||
Bitmap bitmap = null;
|
if (!TextUtils.isEmpty(imagePath)) {
|
||||||
if (!TextUtils.isEmpty(imagePath)) {
|
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
||||||
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
// Try to load the bitmap from the file system
|
||||||
// Try to load the bitmap from the file system
|
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
||||||
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
// Try to load the bitmap from the assets directory
|
||||||
// Try to load the bitmap from the assets directory
|
AssetManager am = getContext().getAssets();
|
||||||
AssetManager am = getContext().getAssets();
|
InputStream imageInputStream = am.open(imagePath);
|
||||||
InputStream imageInputStream = am.open(imagePath);
|
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
||||||
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY);
|
|
||||||
customPointerIcons.put(pointerType, customPointerIcon);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Reset the custom pointer icon
|
|
||||||
customPointerIcons.delete(pointerType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY);
|
||||||
|
customPointerIcons.put(pointerType, customPointerIcon);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Reset the custom pointer icon
|
||||||
|
customPointerIcons.delete(pointerType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,21 +225,16 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
|
||||||
@Keep
|
@Keep
|
||||||
@Override
|
@Override
|
||||||
public void setPointerIcon(int pointerType) {
|
public void setPointerIcon(int pointerType) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
if (pointerIcon == null) {
|
||||||
if (pointerIcon == null) {
|
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
|
||||||
}
|
|
||||||
setPointerIcon(pointerIcon);
|
|
||||||
}
|
}
|
||||||
|
setPointerIcon(pointerIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
|
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
return getPointerIcon();
|
||||||
return getPointerIcon();
|
|
||||||
}
|
|
||||||
return super.onResolvePointerIcon(me, pointerIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(XRMode xrMode, boolean translucent, boolean useDebugOpengl) {
|
private void init(XRMode xrMode, boolean translucent, boolean useDebugOpengl) {
|
||||||
|
|
|
@ -64,9 +64,7 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
||||||
this.godot = godot;
|
this.godot = godot;
|
||||||
mInputHandler = inputHandler;
|
mInputHandler = inputHandler;
|
||||||
mRenderer = new VkRenderer();
|
mRenderer = new VkRenderer();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
|
||||||
setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
|
|
||||||
}
|
|
||||||
setFocusableInTouchMode(true);
|
setFocusableInTouchMode(true);
|
||||||
setClickable(false);
|
setClickable(false);
|
||||||
}
|
}
|
||||||
|
@ -179,27 +177,25 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
||||||
@Keep
|
@Keep
|
||||||
@Override
|
@Override
|
||||||
public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) {
|
public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) {
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
try {
|
||||||
try {
|
Bitmap bitmap = null;
|
||||||
Bitmap bitmap = null;
|
if (!TextUtils.isEmpty(imagePath)) {
|
||||||
if (!TextUtils.isEmpty(imagePath)) {
|
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
||||||
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
// Try to load the bitmap from the file system
|
||||||
// Try to load the bitmap from the file system
|
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
||||||
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
// Try to load the bitmap from the assets directory
|
||||||
// Try to load the bitmap from the assets directory
|
AssetManager am = getContext().getAssets();
|
||||||
AssetManager am = getContext().getAssets();
|
InputStream imageInputStream = am.open(imagePath);
|
||||||
InputStream imageInputStream = am.open(imagePath);
|
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
||||||
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY);
|
|
||||||
customPointerIcons.put(pointerType, customPointerIcon);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Reset the custom pointer icon
|
|
||||||
customPointerIcons.delete(pointerType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY);
|
||||||
|
customPointerIcons.put(pointerType, customPointerIcon);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Reset the custom pointer icon
|
||||||
|
customPointerIcons.delete(pointerType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,20 +205,15 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
||||||
@Keep
|
@Keep
|
||||||
@Override
|
@Override
|
||||||
public void setPointerIcon(int pointerType) {
|
public void setPointerIcon(int pointerType) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
if (pointerIcon == null) {
|
||||||
if (pointerIcon == null) {
|
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
|
||||||
}
|
|
||||||
setPointerIcon(pointerIcon);
|
|
||||||
}
|
}
|
||||||
|
setPointerIcon(pointerIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
|
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
return getPointerIcon();
|
||||||
return getPointerIcon();
|
|
||||||
}
|
|
||||||
return super.onResolvePointerIcon(me, pointerIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,9 +103,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
|
||||||
this.gestureDetector = new GestureDetector(context, godotGestureHandler);
|
this.gestureDetector = new GestureDetector(context, godotGestureHandler);
|
||||||
this.gestureDetector.setIsLongpressEnabled(false);
|
this.gestureDetector.setIsLongpressEnabled(false);
|
||||||
this.scaleGestureDetector = new ScaleGestureDetector(context, godotGestureHandler);
|
this.scaleGestureDetector = new ScaleGestureDetector(context, godotGestureHandler);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
this.scaleGestureDetector.setStylusScaleEnabled(true);
|
||||||
this.scaleGestureDetector.setStylusScaleEnabled(true);
|
|
||||||
}
|
|
||||||
Configuration config = context.getResources().getConfiguration();
|
Configuration config = context.getResources().getConfiguration();
|
||||||
hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS &&
|
hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS &&
|
||||||
config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
|
config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
|
||||||
|
@ -297,7 +295,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
|
if (gestureDetector.onGenericMotionEvent(event)) {
|
||||||
// The gesture detector has handled the event.
|
// The gesture detector has handled the event.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,18 +150,10 @@ internal class FilesystemDirectoryAccess(private val context: Context, private v
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDriveCount(): Int {
|
override fun getDriveCount(): Int {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
return storageManager.storageVolumes.size
|
||||||
storageManager.storageVolumes.size
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDrive(drive: Int): String {
|
override fun getDrive(drive: Int): String {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drive < 0 || drive >= storageManager.storageVolumes.size) {
|
if (drive < 0 || drive >= storageManager.storageVolumes.size) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,11 +87,6 @@ public final class PermissionsUtil {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
||||||
// Not necessary, asked on install already
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean dispatchedPermissionsRequest = false;
|
boolean dispatchedPermissionsRequest = false;
|
||||||
Set<String> requestedPermissions = new HashSet<>();
|
Set<String> requestedPermissions = new HashSet<>();
|
||||||
for (String permission : permissions) {
|
for (String permission : permissions) {
|
||||||
|
@ -201,10 +196,6 @@ public final class PermissionsUtil {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> manifestPermissions;
|
List<String> manifestPermissions;
|
||||||
try {
|
try {
|
||||||
manifestPermissions = getManifestPermissions(activity);
|
manifestPermissions = getManifestPermissions(activity);
|
||||||
|
|
|
@ -40,11 +40,10 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
|
||||||
|
|
||||||
_cls = (jclass)env->NewGlobalRef(env->GetObjectClass(godot_view));
|
_cls = (jclass)env->NewGlobalRef(env->GetObjectClass(godot_view));
|
||||||
|
|
||||||
|
_configure_pointer_icon = env->GetMethodID(_cls, "configurePointerIcon", "(ILjava/lang/String;FF)V");
|
||||||
|
_set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
|
||||||
|
|
||||||
int android_device_api_level = android_get_device_api_level();
|
int android_device_api_level = android_get_device_api_level();
|
||||||
if (android_device_api_level >= __ANDROID_API_N__) {
|
|
||||||
_configure_pointer_icon = env->GetMethodID(_cls, "configurePointerIcon", "(ILjava/lang/String;FF)V");
|
|
||||||
_set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
|
|
||||||
}
|
|
||||||
if (android_device_api_level >= __ANDROID_API_O__) {
|
if (android_device_api_level >= __ANDROID_API_O__) {
|
||||||
_request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
|
_request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
|
||||||
_release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
|
_release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue