You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-08 12:40:44 +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:
@@ -1,8 +1,10 @@
|
||||
ext.versions = [
|
||||
androidGradlePlugin: '8.6.1',
|
||||
compileSdk : 35,
|
||||
// Also update 'platform/android/export/export_plugin.cpp#OPENGL_MIN_SDK_VERSION'
|
||||
minSdk : 21,
|
||||
// Also update:
|
||||
// - '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'
|
||||
targetSdk : 35,
|
||||
buildTools : '35.0.0',
|
||||
@@ -382,17 +384,12 @@ ext.shouldNotStrip = { ->
|
||||
*/
|
||||
ext.shouldUseLegacyPackaging = { ->
|
||||
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") : ""
|
||||
if (legacyPackagingFlag != null && !legacyPackagingFlag.isEmpty()) {
|
||||
return Boolean.parseBoolean(legacyPackagingFlag)
|
||||
}
|
||||
|
||||
// Default behavior for minSdk >= 23
|
||||
// Default behavior for minSdk >= 24
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,6 @@ android {
|
||||
}
|
||||
applicationIdSuffix ".meta"
|
||||
versionNameSuffix "-meta"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 32
|
||||
}
|
||||
picoos {
|
||||
|
||||
@@ -192,13 +192,11 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||
Manifest.permission.RECORD_AUDIO,
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
excludedPermissions.add(
|
||||
// The REQUEST_INSTALL_PACKAGES permission is requested the first time we attempt to
|
||||
// open an apk file.
|
||||
Manifest.permission.REQUEST_INSTALL_PACKAGES,
|
||||
)
|
||||
}
|
||||
excludedPermissions.add(
|
||||
// The REQUEST_INSTALL_PACKAGES permission is requested the first time we attempt to
|
||||
// open an apk file.
|
||||
Manifest.permission.REQUEST_INSTALL_PACKAGES,
|
||||
)
|
||||
|
||||
// XR runtime permissions should only be requested when the "xr/openxr/enabled" project setting
|
||||
// is enabled.
|
||||
@@ -384,10 +382,8 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||
|
||||
val launchPolicy = resolveLaunchPolicyIfNeeded(editorWindowInfo.launchPolicy)
|
||||
if (launchPolicy == LaunchPolicy.ADJACENT) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Log.v(TAG, "Adding flag for adjacent launch")
|
||||
newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
|
||||
}
|
||||
Log.v(TAG, "Adding flag for adjacent launch")
|
||||
newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
|
||||
}
|
||||
return newInstance
|
||||
}
|
||||
@@ -511,12 +507,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||
private fun resolveGameEmbedModeIfNeeded(embedMode: GameEmbedMode): GameEmbedMode {
|
||||
return when (embedMode) {
|
||||
GameEmbedMode.AUTO -> {
|
||||
val inMultiWindowMode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
isInMultiWindowMode
|
||||
} else {
|
||||
false
|
||||
}
|
||||
if (inMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
||||
if (isInMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
||||
GameEmbedMode.DISABLED
|
||||
} else {
|
||||
GameEmbedMode.ENABLED
|
||||
@@ -534,12 +525,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
||||
private fun resolveLaunchPolicyIfNeeded(policy: LaunchPolicy): LaunchPolicy {
|
||||
return when (policy) {
|
||||
LaunchPolicy.AUTO -> {
|
||||
val inMultiWindowMode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
isInMultiWindowMode
|
||||
} else {
|
||||
false
|
||||
}
|
||||
val defaultLaunchPolicy = if (inMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
||||
val defaultLaunchPolicy = if (isInMultiWindowMode || isLargeScreen || isNativeXRDevice(applicationContext)) {
|
||||
LaunchPolicy.ADJACENT
|
||||
} else {
|
||||
LaunchPolicy.SAME
|
||||
|
||||
@@ -83,7 +83,7 @@ open class GodotGame : BaseGodotGame() {
|
||||
}
|
||||
|
||||
override fun enterPiPMode() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && hasPiPSystemFeature()) {
|
||||
if (hasPiPSystemFeature()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val builder = PictureInPictureParams.Builder().setSourceRectHint(gameViewSourceRectHint)
|
||||
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).
|
||||
*/
|
||||
protected fun hasPiPSystemFeature(): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
|
||||
packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
||||
return packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
||||
}
|
||||
|
||||
override fun shouldShowGameMenuBar(): Boolean {
|
||||
@@ -123,8 +122,7 @@ open class GodotGame : BaseGodotGame() {
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
|
||||
val isInPiPMode = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInPictureInPictureMode
|
||||
if (isInPiPMode && !isFinishing) {
|
||||
if (isInPictureInPictureMode && !isFinishing) {
|
||||
// We get in this state when PiP is closed, so we terminate the activity.
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -225,19 +225,12 @@ public class Helpers {
|
||||
return path;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
static public String getSaveFilePath(Context c) {
|
||||
// This technically existed since Honeycomb, but it is critical
|
||||
// on KitKat and greater versions since it will create the
|
||||
// directory if needed
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
return c.getObbDir().toString();
|
||||
} else {
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
String path = root.toString() + Constants.EXP_PATH + c.getPackageName();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return c.getObbDir().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* directory to allow an OBB file to be written.
|
||||
*
|
||||
*
|
||||
* @param c the app/activity/service context
|
||||
* @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
|
||||
* {@link IDownloaderClient#onDownloadStateChanged} callback into usable strings. This is useful
|
||||
* if using the state strings built into the library to display user messages.
|
||||
*
|
||||
*
|
||||
* @param state One of the STATE_* constants from {@link IDownloaderClient}.
|
||||
* @return string resource ID for the corresponding string.
|
||||
*/
|
||||
|
||||
@@ -865,16 +865,13 @@ class Godot(private val context: Context) {
|
||||
if (packageManager == null) {
|
||||
return false
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
|
||||
// Optional requirements.. log as warning if missing
|
||||
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)
|
||||
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
|
||||
// Optional requirements.. log as warning if missing
|
||||
Log.w(TAG, "The vulkan hardware level does not meet the minimum requirement: 1")
|
||||
}
|
||||
return false
|
||||
|
||||
// Check for api version 1.0
|
||||
return packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x400003)
|
||||
}
|
||||
|
||||
private fun setKeepScreenOn(enabled: Boolean) {
|
||||
|
||||
@@ -221,14 +221,8 @@ public class GodotFragment extends Fragment implements IDownloaderClient, GodotH
|
||||
Intent notifierIntent = new Intent(activity, activity.getClass());
|
||||
notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
PendingIntent pendingIntent;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
pendingIntent = PendingIntent.getActivity(activity, 0,
|
||||
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
} else {
|
||||
pendingIntent = PendingIntent.getActivity(activity, 0,
|
||||
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(activity, 0,
|
||||
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
|
||||
int startResult;
|
||||
try {
|
||||
|
||||
@@ -90,9 +90,7 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
|
||||
this.godot = godot;
|
||||
this.inputHandler = inputHandler;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -199,27 +197,25 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
|
||||
@Keep
|
||||
@Override
|
||||
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 {
|
||||
Bitmap bitmap = null;
|
||||
if (!TextUtils.isEmpty(imagePath)) {
|
||||
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the file system
|
||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the assets directory
|
||||
AssetManager am = getContext().getAssets();
|
||||
InputStream imageInputStream = am.open(imagePath);
|
||||
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
||||
}
|
||||
try {
|
||||
Bitmap bitmap = null;
|
||||
if (!TextUtils.isEmpty(imagePath)) {
|
||||
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the file system
|
||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the assets directory
|
||||
AssetManager am = getContext().getAssets();
|
||||
InputStream imageInputStream = am.open(imagePath);
|
||||
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
|
||||
@Override
|
||||
public void setPointerIcon(int pointerType) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||
if (pointerIcon == null) {
|
||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||
}
|
||||
setPointerIcon(pointerIcon);
|
||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||
if (pointerIcon == null) {
|
||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||
}
|
||||
setPointerIcon(pointerIcon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
return getPointerIcon();
|
||||
}
|
||||
return super.onResolvePointerIcon(me, pointerIndex);
|
||||
return getPointerIcon();
|
||||
}
|
||||
|
||||
private void init(XRMode xrMode, boolean translucent, boolean useDebugOpengl) {
|
||||
|
||||
@@ -64,9 +64,7 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
||||
this.godot = godot;
|
||||
mInputHandler = inputHandler;
|
||||
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);
|
||||
setClickable(false);
|
||||
}
|
||||
@@ -179,27 +177,25 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
||||
@Keep
|
||||
@Override
|
||||
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 {
|
||||
Bitmap bitmap = null;
|
||||
if (!TextUtils.isEmpty(imagePath)) {
|
||||
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the file system
|
||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the assets directory
|
||||
AssetManager am = getContext().getAssets();
|
||||
InputStream imageInputStream = am.open(imagePath);
|
||||
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
||||
}
|
||||
try {
|
||||
Bitmap bitmap = null;
|
||||
if (!TextUtils.isEmpty(imagePath)) {
|
||||
if (godot.getDirectoryAccessHandler().filesystemFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the file system
|
||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||
} else if (godot.getDirectoryAccessHandler().assetsFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the assets directory
|
||||
AssetManager am = getContext().getAssets();
|
||||
InputStream imageInputStream = am.open(imagePath);
|
||||
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
|
||||
@Override
|
||||
public void setPointerIcon(int pointerType) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||
if (pointerIcon == null) {
|
||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||
}
|
||||
setPointerIcon(pointerIcon);
|
||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||
if (pointerIcon == null) {
|
||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||
}
|
||||
setPointerIcon(pointerIcon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
return getPointerIcon();
|
||||
}
|
||||
return super.onResolvePointerIcon(me, pointerIndex);
|
||||
return getPointerIcon();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +103,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
|
||||
this.gestureDetector = new GestureDetector(context, godotGestureHandler);
|
||||
this.gestureDetector.setIsLongpressEnabled(false);
|
||||
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();
|
||||
hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS &&
|
||||
config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
|
||||
@@ -297,7 +295,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
|
||||
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.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -150,18 +150,10 @@ internal class FilesystemDirectoryAccess(private val context: Context, private v
|
||||
}
|
||||
|
||||
override fun getDriveCount(): Int {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
storageManager.storageVolumes.size
|
||||
} else {
|
||||
0
|
||||
}
|
||||
return storageManager.storageVolumes.size
|
||||
}
|
||||
|
||||
override fun getDrive(drive: Int): String {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (drive < 0 || drive >= storageManager.storageVolumes.size) {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -87,11 +87,6 @@ public final class PermissionsUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
// Not necessary, asked on install already
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean dispatchedPermissionsRequest = false;
|
||||
Set<String> requestedPermissions = new HashSet<>();
|
||||
for (String permission : permissions) {
|
||||
@@ -201,10 +196,6 @@ public final class PermissionsUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<String> manifestPermissions;
|
||||
try {
|
||||
manifestPermissions = getManifestPermissions(activity);
|
||||
|
||||
Reference in New Issue
Block a user