From 9b2657ac620f264922904d1a505d4eacd7416049 Mon Sep 17 00:00:00 2001 From: Ethan O'Brien <77750390+ethanaobrien@users.noreply.github.com> Date: Sat, 2 Aug 2025 04:26:33 -0500 Subject: [PATCH] Update android targetsdk to 36 (#24843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update targetsdk to 36 * Combine duplicate code into a method * Update dependencies and cmake * Update Android base image * Add TODO note above all file access intent --------- Co-authored-by: MichaƂ Janiszewski --- .github/workflows/ci.yml | 2 +- distribution/changelog.txt | 1 + src/openrct2-android/app/build.gradle | 16 +++--- .../app/src/main/AndroidManifest.xml | 13 +++-- .../main/java/io/openrct2/GameActivity.java | 23 ++++----- .../main/java/io/openrct2/MainActivity.java | 49 +++++++++++++++---- src/openrct2-android/build.gradle | 4 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 8 files changed, 74 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2fc8bec59..d8d906ad8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -605,7 +605,7 @@ jobs: name: Android runs-on: ubuntu-latest needs: [check-code-formatting, build_variables] - container: openrct2/openrct2-build:18-android + container: openrct2/openrct2-build:20-android steps: - name: Checkout uses: actions/checkout@v4 diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 0a507ed367..3f756a6f32 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -6,6 +6,7 @@ - Improved: [#24812] Taiwan Park has been added to the Extras tab if it is present. - Improved: [OpenSFX#12] Add Brake Fix, Buy and Dinghy Slide running sounds. - Change: [#24730] Security guards now only walk slowly in crowded areas. +- Change: [#24843] Update android targetSDK to 36. - Fix: [#24598] Cannot load .park files that use official legacy footpaths by accident. - Fix: [#24611] The confirmation prompt for track file deletion is not vertically aligned. - Fix: [#24711] The map smoothing function only partially works for custom height map image files. diff --git a/src/openrct2-android/app/build.gradle b/src/openrct2-android/app/build.gradle index 2edad3fb43..a541437327 100644 --- a/src/openrct2-android/app/build.gradle +++ b/src/openrct2-android/app/build.gradle @@ -1,14 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdk 35 - buildToolsVersion "35.0.0" - ndkVersion "27.2.12479018" // Latest r27c (LTS), to be synced with CI container image + compileSdk 36 + ndkVersion "27.3.13750724" // Latest r27d (LTS), to be synced with CI container image namespace "io.openrct2" defaultConfig { applicationId 'io.openrct2' minSdkVersion 24 - targetSdkVersion 28 + targetSdkVersion 36 versionCode 12 versionName '0.4.24' @@ -35,6 +34,7 @@ android { } externalNativeBuild { cmake { + version "4.0.3" path 'src/main/CMakeLists.txt' } } @@ -45,8 +45,12 @@ android { } dependencies { - implementation 'commons-io:commons-io:2.13.0' - implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'commons-io:commons-io:2.20.0' + implementation 'androidx.appcompat:appcompat:1.7.1' implementation fileTree(include: ['*.jar'], dir: 'libs') } +configurations.implementation { + exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8' +} + diff --git a/src/openrct2-android/app/src/main/AndroidManifest.xml b/src/openrct2-android/app/src/main/AndroidManifest.xml index f2b3034d05..1969d9cdf4 100644 --- a/src/openrct2-android/app/src/main/AndroidManifest.xml +++ b/src/openrct2-android/app/src/main/AndroidManifest.xml @@ -1,10 +1,15 @@ - + - - + + + + tools:targetApi="36"> = Build.VERSION_CODES.N) { - deviceLocale = getResources().getConfiguration().getLocales().get(0); + return getResources().getConfiguration().getLocales().get(0); } else { - deviceLocale = getResources().getConfiguration().locale; + return getResources().getConfiguration().locale; } + } + public String getDefaultLocale(String[] supportedTags) { + Locale deviceLocale = getDeviceLocale(); for (String supportedTag : supportedTags) { if (supportedTag.isEmpty()) continue; @@ -51,26 +55,19 @@ public class GameActivity extends SDLActivity { } public String getLocaleCurrency() { - Locale deviceLocale; + Locale deviceLocale = getDeviceLocale(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - deviceLocale = getResources().getConfiguration().getLocales().get(0); return Currency.getInstance(deviceLocale).getCurrencyCode(); } else { - deviceLocale = getResources().getConfiguration().locale; return java.util.Currency.getInstance(deviceLocale).getCurrencyCode(); } } public boolean isImperialLocaleMeasurementFormat() { - Locale deviceLocale; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { return LocaleData.getMeasurementSystem(ULocale.forLocale(getResources().getConfiguration().getLocales().get(0))) == LocaleData.MeasurementSystem.US; } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - deviceLocale = getResources().getConfiguration().getLocales().get(0); - } else { - deviceLocale = getResources().getConfiguration().locale; - } + Locale deviceLocale = getDeviceLocale(); String localeCountry = deviceLocale.getCountry(); return localeCountry.equals(Locale.US.getCountry()) || localeCountry.equals(new Locale("xx", "LR").getCountry()) || localeCountry.equals(new Locale("xx", "MM").getCountry()); } diff --git a/src/openrct2-android/app/src/main/java/io/openrct2/MainActivity.java b/src/openrct2-android/app/src/main/java/io/openrct2/MainActivity.java index cb4a584566..708d7d7fb2 100644 --- a/src/openrct2-android/app/src/main/java/io/openrct2/MainActivity.java +++ b/src/openrct2-android/app/src/main/java/io/openrct2/MainActivity.java @@ -6,6 +6,7 @@ import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.graphics.Point; import android.graphics.PointF; +import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -94,22 +95,52 @@ public class MainActivity extends AppCompatActivity { super.onStart(); if (!hasRequiredPermissions()) { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + /* + TODO - This is a temporary solution + Ideally, OpenRCT2 assets should be shipped in the apk and we should ask + the user for their rct2 assets directory on boot (similar to windows). + Save data should be stored under the "external data directory", + which you can get via `getExternalFilesDir(null).getAbsolutePath()` + */ + Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); + intent.addCategory("android.intent.category.DEFAULT"); + intent.setData(Uri.fromParts("package", getPackageName(), null)); + startActivity(intent); + } else { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + } } else { startGame(); } } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == 0) { + if (!hasRequiredPermissions()) { + Log.d(TAG, "User denied storage permission!"); + } else { + startGame(); + } + } + } + private boolean hasRequiredPermissions() { - if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { - return false; - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return Environment.isExternalStorageManager(); + } else { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + return false; + } - if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { - return false; - } + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + return false; + } - return true; + return true; + } } private void startGame() { @@ -162,7 +193,7 @@ public class MainActivity extends AppCompatActivity { for (String fileName : list) { // This ternary expression makes sure that this string does not begin with a slash - String destination = destPath + (destPath.equals("") ? "" : File.separator) + fileName; + String destination = destPath + (destPath.isEmpty() ? "" : File.separator) + fileName; copyAsset(assets, srcPath + File.separator + fileName, dataDir, destination); } } diff --git a/src/openrct2-android/build.gradle b/src/openrct2-android/build.gradle index ed2299cb0d..80450e4144 100644 --- a/src/openrct2-android/build.gradle +++ b/src/openrct2-android/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.7.3' + classpath 'com.android.tools.build:gradle:8.11.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -20,6 +20,6 @@ allprojects { } } -task clean(type: Delete) { +tasks.register('clean', Delete) { delete rootProject.buildDir } diff --git a/src/openrct2-android/gradle/wrapper/gradle-wrapper.properties b/src/openrct2-android/gradle/wrapper/gradle-wrapper.properties index e2847c8200..d4081da476 100644 --- a/src/openrct2-android/gradle/wrapper/gradle-wrapper.properties +++ b/src/openrct2-android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME