LibGDX Update

This commit is contained in:
Anthony Calosa
2024-08-04 12:47:39 +08:00
parent 7d1e9a4c64
commit 2cd3347429
50 changed files with 658 additions and 288 deletions

View File

@@ -12,8 +12,11 @@
<name>Forge Adventure</name> <name>Forge Adventure</name>
<repositories> <repositories>
<repository> <repository>
<id>gdx-nightlies</id> <id>4thline-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url> <url>http://4thline.org/m2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository> </repository>
<repository> <repository>
<id>jitpack.io</id> <id>jitpack.io</id>
@@ -29,6 +32,7 @@
<include>**/*.vert</include> <include>**/*.vert</include>
<include>**/*.frag</include> <include>**/*.frag</include>
<include>**/title_bg_lq.png</include> <include>**/title_bg_lq.png</include>
<include>**/title_bg_lq_portrait.png</include>
<include>**/transition.png</include> <include>**/transition.png</include>
<include>**/adv_bg_texture.jpg</include> <include>**/adv_bg_texture.jpg</include>
<include>**/adv_bg_splash.png</include> <include>**/adv_bg_splash.png</include>
@@ -231,36 +235,36 @@
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId> <artifactId>gdx</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-platform</artifactId> <artifactId>gdx-platform</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<classifier>natives-desktop</classifier> <classifier>natives-desktop</classifier>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-freetype</artifactId> <artifactId>gdx-freetype</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-lwjgl</artifactId> <artifactId>gdx-backend-lwjgl</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-tools</artifactId> <artifactId>gdx-tools</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-freetype-platform</artifactId> <artifactId>gdx-freetype-platform</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<classifier>natives-desktop</classifier> <classifier>natives-desktop</classifier>
</dependency> </dependency>
<dependency> <dependency>
@@ -287,7 +291,13 @@
<dependency> <dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId> <groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-desktop</artifactId> <artifactId>gdx-controllers-desktop</artifactId>
<version>2.2.3-SNAPSHOT</version> <version>2.2.3</version>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>32.0.0-android</version> <version>33.2.1-android</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>

View File

@@ -5,10 +5,11 @@
android:versionName="1.6.64" > <!-- versionName should be updated and it's used for Sentry releases tag --> android:versionName="1.6.64" > <!-- versionName should be updated and it's used for Sentry releases tag -->
<uses-sdk <uses-sdk
android:minSdkVersion="19" android:minSdkVersion="26"
android:targetSdkVersion="26" /> android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
@@ -24,17 +25,9 @@
android:label="@string/app_name" android:label="@string/app_name"
android:largeHeap="true"> android:largeHeap="true">
<activity <activity
android:name=".Main" android:name=".Launcher"
android:label="@string/app_name" android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode" android:theme="@style/Theme.Transparent">
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:exported="false">
</activity>
<activity
android:name=".Launcher"
android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
android:theme="@android:style/Theme.Black.NoTitleBar">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
@@ -45,8 +38,26 @@
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".Main"
android:label="@string/app_name"
android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:exported="false">
</activity>
<meta-data android:name="io.sentry.dsn" android:value="https://a0b8dbad9b8a49cfa51bf65d462e8dae:b3f27d7461224cb8836eb5c6050c666c@sentry.cardforge.org/2?buffer.enabled=false" /> <meta-data android:name="io.sentry.dsn" android:value="https://a0b8dbad9b8a49cfa51bf65d462e8dae:b3f27d7461224cb8836eb5c6050c666c@sentry.cardforge.org/2?buffer.enabled=false" />
<meta-data android:name="io.sentry.anr.enable" android:value="false" />
<!-- To disable the activity lifecycle breadcrumbs integration -->
<meta-data android:name="io.sentry.breadcrumbs.activity-lifecycle" android:value="false" />
<!-- To disable the app lifecycle breadcrumbs integration -->
<meta-data android:name="io.sentry.breadcrumbs.app-lifecycle" android:value="false" />
<!-- To disable the system events breadcrumbs integration -->
<meta-data android:name="io.sentry.breadcrumbs.system-events" android:value="false" />
<!-- To disable the app components breadcrumbs integration -->
<meta-data android:name="io.sentry.breadcrumbs.app-components" android:value="false" />
<!-- To disable the user interaction breadcrumbs integration -->
<meta-data android:name="io.sentry.breadcrumbs.user-interaction" android:value="false" />
<!-- manually added --> <!-- manually added -->
<provider <provider
android:name="io.sentry.android.core.SentryInitProvider" android:name="io.sentry.android.core.SentryInitProvider"
@@ -57,5 +68,15 @@
android:authorities=".SentryPerformanceProvider" android:authorities=".SentryPerformanceProvider"
android:initOrder="200" android:initOrder="200"
android:exported="false"/> android:exported="false"/>
<provider
android:name="de.cketti.fileprovider.PublicFileProvider"
android:authorities="com.mydomain.publicfileprovider"
android:exported="true">
<meta-data
android:name="de.cketti.fileprovider.PUBLIC_FILE_PROVIDER_PATHS"
android:resource="@xml/publicfileprovider_paths" />
</provider>
</application> </application>
</manifest> </manifest>

View File

@@ -0,0 +1 @@
${timestamp}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2,7 +2,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format> <timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<packaging.type>jar</packaging.type> <packaging.type>jar</packaging.type>
<build.min.memory>-Xms1024m</build.min.memory> <build.min.memory>-Xms1024m</build.min.memory>
<build.max.memory>-Xmx1536m</build.max.memory> <build.max.memory>-Xmx1536m</build.max.memory>
@@ -26,6 +27,13 @@
<packaging>${packaging.type}</packaging> <packaging>${packaging.type}</packaging>
<name>Forge Android</name> <name>Forge Android</name>
<repositories>
<repository>
<id>Google Maven</id>
<url>https://maven.google.com/</url>
</repository>
</repositories>
<build> <build>
<sourceDirectory>src</sourceDirectory> <sourceDirectory>src</sourceDirectory>
<plugins> <plugins>
@@ -45,30 +53,44 @@
</resources> </resources>
<finalName>forge-android-${alpha-version}</finalName> <finalName>forge-android-${alpha-version}</finalName>
</build> </build>
<repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.google.android</groupId> <groupId>org.robolectric</groupId>
<artifactId>android</artifactId> <artifactId>android-all</artifactId>
<version>4.1.1.4</version> <version>8.0.0_r4-robolectric-0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>de.cketti.fileprovider</groupId>
<artifactId>public-fileprovider</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${pom.basedir}/libs/publicfileprovider.jar</systemPath>
</dependency>
<dependency>
<groupId>com.getkeepsafe.relinker</groupId>
<artifactId>relinker</artifactId>
<version>1.4.5</version>
<scope>system</scope>
<systemPath>${pom.basedir}/libs/relinker.jar</systemPath>
</dependency>
<!-- declare a specific dependency to override com.google.android's transitive dependency --> <!-- declare a specific dependency to override com.google.android's transitive dependency -->
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
<version>4.5.13</version> <version>4.5.14</version>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- declare a specific dependency to override org.apache.httpcomponents's transitive dependency --> <!-- declare a specific dependency to override org.apache.httpcomponents's transitive dependency -->
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId> <artifactId>commons-codec</artifactId>
<version>1.15</version> <version>1.16.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>forge</groupId> <groupId>forge</groupId>
@@ -104,7 +126,9 @@
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-android</artifactId> <artifactId>gdx-backend-android</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<scope>system</scope>
<systemPath>${pom.basedir}/libs/gdx-backend-android.jar</systemPath>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.sentry</groupId> <groupId>io.sentry</groupId>
@@ -176,8 +200,14 @@
<dependency> <dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId> <groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-android</artifactId> <artifactId>gdx-controllers-android</artifactId>
<version>2.2.3-SNAPSHOT</version> <version>2.2.3</version>
<type>aar</type> <type>aar</type>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-android</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -423,6 +453,11 @@
<exclude name="res/cardsfolder/**" /> <exclude name="res/cardsfolder/**" />
</fileset> </fileset>
</copy> </copy>
<copy todir="${project.build.directory}/res/res">
<fileset dir="${project.build.directory}/classes">
<include name="build.txt" />
</fileset>
</copy>
<mkdir dir="${project.build.directory}/res/res/cardsfolder" /> <mkdir dir="${project.build.directory}/res/res/cardsfolder" />
<zip destfile="${project.build.directory}/res/res/cardsfolder/cardsfolder.zip" basedir="${basedir}/../forge-gui/res/cardsfolder" level="1" /> <zip destfile="${project.build.directory}/res/res/cardsfolder/cardsfolder.zip" basedir="${basedir}/../forge-gui/res/cardsfolder" level="1" />
<zip destfile="${project.build.directory}/assets.zip" basedir="${project.build.directory}/res" level="1" /> <zip destfile="${project.build.directory}/assets.zip" basedir="${project.build.directory}/res" level="1" />

View File

@@ -4,12 +4,16 @@
-dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclasses
-dontpreverify -dontpreverify
-verbose -verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable -optimizations !code/simplification/*,!field/*,!class/merging/*,!code/allocation/variable,!library/gson
## Uncomment the line below and set it to the location of rt.jar in JDK if the Proguard step fails to find the libraries ## Uncomment the line below and set it to the location of rt.jar in JDK if the Proguard step fails to find the libraries
## and spits out a thousand-something Class Not Found errors ## and spits out a thousand-something Class Not Found errors
##-libraryjars /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar ##-libraryjars /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar
##-libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) ##-libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class)
##-libraryjars <java.home>/jmods/java.datatransfer.jmod(!**.jar;!module-info.class)
##-libraryjars <java.home>/jmods/java.prefs.jmod(!**.jar;!module-info.class)
##-libraryjars <java.home>/jmods/java.xml.jmod(!**.jar;!module-info.class)
##-libraryjars <java.home>/jmods/java.desktop.jmod(!**.jar;!module-info.class)
##-libraryjars <java.home>/jmods/jdk.xml.dom.jmod(!**.jar;!module-info.class) ##-libraryjars <java.home>/jmods/jdk.xml.dom.jmod(!**.jar;!module-info.class)
-dontwarn afu.org.checkerframework.** -dontwarn afu.org.checkerframework.**
@@ -57,18 +61,20 @@
-keep class org.apache.commons.lang3.** { *; } -keep class org.apache.commons.lang3.** { *; }
-keep class com.google.guava.** { *; } -keep class com.google.guava.** { *; }
-keep class com.google.common.** { *; } -keep class com.google.common.** { *; }
-keep class com.google.gson.GsonBuilder #-keep class com.google.gson.GsonBuilder
-keep class io.sentry.event.Event { *; } ##-keep class io.sentry.event.Event { *; }
-keep class io.sentry.android.core.SentryAndroidOptions ##-keep class io.sentry.android.core.SentryAndroidOptions
-keep class io.sentry.android.core.SentryAndroid ##-keep class io.sentry.android.core.SentryAndroid
-keep class io.sentry.android.core.SentryInitProvider ##-keep class io.sentry.android.core.SentryInitProvider
-keep class io.sentry.android.core.SentryPerformanceProvider ##-keep class io.sentry.android.core.SentryPerformanceProvider
-keep class com.badlogic.gdx.controllers.android.AndroidControllers { *; } -keep class com.badlogic.gdx.controllers.android.AndroidControllers { *; }
-keep class com.github.tommyettinger.textra.** { *; } -keep class com.github.tommyettinger.textra.** { *; }
-keep class io.sentry.android.ndk.SentryNdk ##-keep class io.sentry.android.ndk.SentryNdk
-keep class io.sentry.Sentry ##-keep class io.sentry.Sentry
-keep class io.sentry.** { *; }
-keepclassmembers enum io.sentry.** { *; }
-keep class io.netty.util.internal.logging.** { *; } -keep class io.netty.util.internal.logging.** { *; }
-keep class net.jpountz.** { *; } -keep class net.jpountz.** { *; }
-keep class com.ray3k.** { *; } -keep class com.ray3k.** { *; }

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:type="linear"
android:angle="135"
android:startColor="#24476B"
android:endColor="#0C335B" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_gradient"/>
<item>
<bitmap android:src="@drawable/logo" android:gravity="center"/>
</item>
</layer-list>

View File

@@ -1,7 +1,38 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:id="@+id/mainview"
android:layout_height="fill_parent" android:layout_width="match_parent"
android:orientation="vertical" > android:layout_height="match_parent"
android:gravity="center"
android:background="@color/splashBackground">
</LinearLayout> <ImageView
android:id="@+id/logo_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxHeight="400dp"
android:adjustViewBounds="true"
android:layout_gravity="center_horizontal"
android:src="@drawable/logo"/>
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:id="@+id/pBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:max="100"
android:progress="0"
android:minWidth="400dp"
android:layout_marginTop="20dp"
android:layout_gravity="center_horizontal"
android:layout_below="@+id/logo_id"/>
<TextView
android:id="@+id/pText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_alignLeft="@+id/pBar"
android:layout_gravity="center_horizontal"
android:layout_below="@+id/pBar"/>
</RelativeLayout>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@color/splashBackground">
</RelativeLayout>

View File

@@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="blue">#258cec</color>
<color name="splashBackground">#000000</color>
</resources>

View File

@@ -0,0 +1,5 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Transparent" parent="android:Theme.Dialog">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="SplashTheme" parent="@android:style/Theme.NoTitleBar.Fullscreen">
<item name="android:windowBackground">@drawable/splash_background</item>
</style>
</resources>

View File

@@ -0,0 +1,11 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<files-path
name="files"
path="." />
</paths>

View File

@@ -5,6 +5,7 @@ import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import forge.gui.GuiBase; import forge.gui.GuiBase;
import java.io.BufferedReader; import java.io.BufferedReader;
@@ -20,9 +21,13 @@ public class Launcher extends Activity {
startActivity(main); startActivity(main);
Intent intent = getIntent(); Intent intent = getIntent();
String action = intent.getAction(); sendIntent(intent, intent.getAction(), intent.getType());
String type = intent.getType();
finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
private void sendIntent(Intent intent, String action, String type) {
if (Intent.ACTION_SEND.equals(action) && type != null) { if (Intent.ACTION_SEND.equals(action) && type != null) {
final Handler handler = new Handler(); final Handler handler = new Handler();
handler.postDelayed(() -> { handler.postDelayed(() -> {
@@ -50,9 +55,7 @@ public class Launcher extends Activity {
} }
}, 1500); }, 1500);
} }
finish();
} }
@Override @Override
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
@@ -61,8 +64,7 @@ public class Launcher extends Activity {
String type = intent.getType(); String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) { if (Intent.ACTION_SEND.equals(action) && type != null) {
final Handler handler = new Handler(); new Handler(Looper.getMainLooper()).postDelayed(() -> {
handler.postDelayed(() -> {
if ("text/plain".equals(type)) { if ("text/plain".equals(type)) {
Uri textUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); Uri textUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (textUri != null) { if (textUri != null) {

View File

@@ -1,32 +1,26 @@
package forge.app; package forge.app;
import java.io.File; import android.animation.Animator;
import java.io.InputStream; import android.animation.AnimatorListenerAdapter;
import java.io.OutputStream; import android.animation.AnimatorSet;
import java.text.Normalizer; import android.animation.ObjectAnimator;
import java.util.ArrayList;
import android.graphics.Point;
import android.view.InputDevice;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Version;
import com.badlogic.gdx.backends.android.AndroidApplication;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.StateListDrawable;
@@ -36,35 +30,57 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.PowerManager;
import android.provider.Settings; import android.provider.Settings;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.Display; import android.view.Display;
import android.view.Gravity; import android.view.Gravity;
import android.view.InputDevice;
import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TableLayout; import android.widget.TableLayout;
import android.widget.TableRow; import android.widget.TableRow;
import android.widget.TextView; import android.widget.TextView;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Version;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.badlogic.gdx.backends.android.AndroidAudio;
import com.getkeepsafe.relinker.ReLinker;
import de.cketti.fileprovider.PublicFileProvider;
import forge.Forge; import forge.Forge;
import forge.interfaces.IDeviceAdapter; import forge.interfaces.IDeviceAdapter;
import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.ThreadUtil; import forge.util.ThreadUtil;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
//import io.sentry.android.core.SentryAndroid;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.Normalizer;
import java.util.ArrayList;
public class Main extends AndroidApplication { public class Main extends AndroidApplication {
AndroidAdapter Gadapter; private AndroidAdapter Gadapter;
ArrayList<String> gamepads; private ArrayList<String> gamepads;
AndroidClipboard androidClipboard; private AndroidClipboard androidClipboard;
boolean hasLaunched; private boolean isMIUI;
private String ASSETS_DIR = "";
private SharedPreferences sharedPreferences;
private int mShortAnimationDuration;
private View forgeLogo = null, forgeView = null, activeView = null;
private ProgressBar progressBar;
private TextView progressText;
private AndroidClipboard getAndroidClipboard() { private AndroidClipboard getAndroidClipboard() {
if (androidClipboard == null) if (androidClipboard == null)
@@ -72,16 +88,62 @@ public class Main extends AndroidApplication {
return androidClipboard; return androidClipboard;
} }
public static boolean isMiUi() {
return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.name"));
}
public static String getSystemProperty(String propName) {
String line;
BufferedReader input = null;
try {
java.lang.Process p = Runtime.getRuntime().exec("getprop " + propName);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return line;
}
@Override
protected void onResume() {
try {
super.onResume();
} catch (Exception e) {
}
}
@Override
public AndroidAudio createAudio(Context context, AndroidApplicationConfiguration config) {
return super.createAudio(context, config);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
gamepads = getGameControllers(); setContentView(getResources().getIdentifier("main", "layout", getPackageName()));
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
sharedPreferences = getPreferences(Context.MODE_PRIVATE);
progressBar = findViewById(getResources().getIdentifier("pBar", "id", getPackageName()));
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.GONE);
progressText = findViewById(getResources().getIdentifier("pText", "id", getPackageName()));
progressText.setVisibility(View.GONE);
if (hasLaunched) isMIUI = isMiUi();
return; if (isMIUI)
hasLaunched = true; preventSleep(true);
//init Sentry
//SentryAndroid.init(this); gamepads = getGameControllers();
//get total device RAM in mb //get total device RAM in mb
ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
@@ -89,51 +151,84 @@ public class Main extends AndroidApplication {
actManager.getMemoryInfo(memInfo); actManager.getMemoryInfo(memInfo);
int totalMemory = Math.round(memInfo.totalMem / 1024f / 1024f); int totalMemory = Math.round(memInfo.totalMem / 1024f / 1024f);
boolean permissiongranted = checkPermission(); boolean permissiongranted = checkPermission();
Gadapter = new AndroidAdapter(this.getContext()); Gadapter = new AndroidAdapter(getContext());
initForge(Gadapter, permissiongranted, totalMemory, isTabletDevice(this.getContext()), Build.VERSION.SDK_INT, Build.VERSION.RELEASE); initForge(Gadapter, permissiongranted, totalMemory, isTabletDevice(getContext()));
} }
private void crossfade(View contentView, View previousView) {
activeView = contentView;
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
contentView.setAlpha(0f);
contentView.setVisibility(View.VISIBLE);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
addContentView(contentView, params);
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
contentView.animate()
.alpha(1f)
.setDuration(mShortAnimationDuration)
.setListener(null);
// Animate the loading view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
previousView.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
previousView.setVisibility(View.GONE);
}
});
}
private static boolean isTabletDevice(Context activityContext) { private static boolean isTabletDevice(Context activityContext) {
Display display = ((Activity) activityContext).getWindowManager().getDefaultDisplay(); Display display = ((Activity) activityContext).getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics(); DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics); display.getMetrics(metrics);
float widthInches = metrics.widthPixels / metrics.xdpi; float widthInches = metrics.widthPixels / metrics.xdpi;
float heightInches = metrics.heightPixels / metrics.ydpi; float heightInches = metrics.heightPixels / metrics.ydpi;
double diagonalInches = Math.sqrt(Math.pow(widthInches, 2) + Math.pow(heightInches, 2)); double diagonalInches = Math.sqrt(Math.pow(widthInches, 2) + Math.pow(heightInches, 2));
if (diagonalInches >= 7.0) { return diagonalInches >= 7.0;
return true;
}
return false;
} }
private void displayMessage(AndroidAdapter adapter, boolean ex, String msg){
private void displayMessage(View previousView, AndroidAdapter adapter, boolean ex, String msg, boolean manageApp) {
TableLayout TL = new TableLayout(this); TableLayout TL = new TableLayout(this);
TL.setBackgroundResource(android.R.color.black);
TableRow row = new TableRow(this); TableRow row = new TableRow(this);
TableRow row2 = new TableRow(this); TableRow row2 = new TableRow(this);
TextView text = new TextView(this); TextView text = new TextView(this);
text.setGravity(Gravity.LEFT); text.setGravity(Gravity.LEFT);
text.setTypeface(Typeface.SERIF); text.setTypeface(Typeface.SERIF);
String SP = Build.VERSION.SDK_INT > 29 ? "Files & Media" : "Storage Permission";
String title="Forge needs Storage Permission to run properly...\n" + String title = "Forge needs " + SP + " to run properly...\n" +
"Follow these simple steps:\n\n"; "Follow these simple steps:\n\n";
String steps = " 1) Tap \"Open App Details\" Button.\n" + String steps = " 1) Tap \"App Settings\" Button.\n" +
" 2) Tap Permissions\n"+ " 2) Tap Permissions\n" +
" 3) Turn on the Storage Permission.\n\n"+ " 3) Enable the " + SP + ".\n\n" +
"(You can tap anywhere to exit and restart the app)\n\n"; "(You can tap anywhere to exit and restart the app)\n\n";
if (ex) { if (ex) {
title = "Forge didn't initialize!\n"; title = manageApp ? "Forge AutoUpdater Permission...\n" : "Forge didn't initialize!\n";
steps = msg + "\n\n"; steps = manageApp ? " 1) Tap \"App Settings\" Button.\n" +
" 2) Enable \"Allow apps from this source\"\n" +
"(You can tap anywhere to exit and restart the app)\n\n" : msg + "\n\n";
} }
SpannableString ss1= new SpannableString(title); SpannableString ss1 = new SpannableString(title);
ss1.setSpan(new StyleSpan(Typeface.BOLD), 0, ss1.length(), 0); ss1.setSpan(new StyleSpan(Typeface.BOLD), 0, ss1.length(), 0);
text.append(ss1); text.append(ss1);
text.append(steps); text.append(steps);
row.addView(text); row.addView(text);
row.setGravity(Gravity.CENTER); row.setGravity(Gravity.CENTER);
int[] colors = {Color.TRANSPARENT,Color.TRANSPARENT}; int[] colors = {Color.TRANSPARENT, Color.TRANSPARENT};
int[] pressed = {Color.GREEN,Color.GREEN}; int[] pressed = {Color.GREEN, Color.GREEN};
GradientDrawable gd = new GradientDrawable( GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, colors); GradientDrawable.Orientation.TOP_BOTTOM, colors);
gd.setStroke(3, Color.DKGRAY); gd.setStroke(3, Color.DKGRAY);
@@ -145,21 +240,29 @@ public class Main extends AndroidApplication {
gd2.setCornerRadius(100); gd2.setCornerRadius(100);
Button button = new Button(this); Button button = new Button(this);
button.setText("Open App Details"); button.setText("App Settings");
button.setTypeface(Typeface.DEFAULT_BOLD);
StateListDrawable states = new StateListDrawable(); StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed}, gd2); states.addState(new int[]{android.R.attr.state_pressed}, gd2);
states.addState(new int[] { }, gd); states.addState(new int[]{}, gd);
button.setBackground(states); button.setBackground(states);
button.setTextColor(Color.RED);
button.setOnClickListener(v -> { button.setOnClickListener(v -> {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); if (manageApp) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
Uri uri = Uri.fromParts("package", getPackageName(), null); .setData(Uri.parse(String.format("package:%s", getPackageName())))
intent.setData(uri); .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); startActivity(intent);
} else {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.parse(String.format("package:%s", getPackageName())))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}); });
row2.addView(button); row2.addView(button);
@@ -168,121 +271,189 @@ public class Main extends AndroidApplication {
TL.addView(row, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT)); TL.addView(row, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.addView(row2, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT)); TL.addView(row2, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.setGravity(Gravity.CENTER); TL.setGravity(Gravity.CENTER);
TL.setOnClickListener(v -> adapter.exit()); TL.setOnClickListener(v -> adapter.restart());
setContentView(TL); crossfade(TL, previousView);
} }
private void loadGame(final String title, final String steps, boolean isLandscape, AndroidAdapter adapter, boolean permissiongranted, int totalRAM, boolean isTabletDevice, AndroidApplicationConfiguration config, boolean exception, String msg) {
try {
forgeLogo = findViewById(getResources().getIdentifier("logo_id", "id", getPackageName()));
forgeView = initializeForView(Forge.getApp(getAndroidClipboard(), adapter, ASSETS_DIR, false, !isLandscape, totalRAM, isTabletDevice, Build.VERSION.SDK_INT, Build.VERSION.RELEASE, getDeviceName()), config);
getAnimator(ObjectAnimator.ofFloat(forgeLogo, "alpha", 0f, 1f).setDuration(1800), null, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (!permissiongranted || exception) {
displayMessage(forgeLogo, adapter, exception, msg, false);
} else if (title.isEmpty() && steps.isEmpty()) {
if (isLandscape) {
Main.this.setRequestedOrientation(Build.VERSION.SDK_INT >= 26 ?
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE : //Oreo and above has virtual back/menu buttons
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
crossfade(forgeView, forgeLogo);
} else {
if (sharedPreferences.getBoolean("run_anyway", false)) {
crossfade(forgeView, forgeLogo);
return;
}
TableLayout TL = new TableLayout(getContext());
TL.setBackgroundResource(android.R.color.black);
TableRow messageRow = new TableRow(getContext());
TableRow checkboxRow = new TableRow(getContext());
TableRow buttonRow = new TableRow(getContext());
TextView text = new TextView(getContext());
text.setGravity(Gravity.LEFT);
text.setTypeface(Typeface.SERIF);
SpannableString ss1 = new SpannableString(title);
ss1.setSpan(new StyleSpan(Typeface.BOLD), 0, ss1.length(), 0);
text.append(ss1);
text.append(steps + "\n");
messageRow.addView(text);
messageRow.setGravity(Gravity.CENTER);
CheckBox checkBox = new CheckBox(getContext());
checkBox.setTypeface(Typeface.SERIF);
checkBox.setGravity(Gravity.TOP);
checkBox.setChecked(false);
checkBox.setPadding(30, 30, 30, 30);
checkBox.setTypeface(Typeface.SERIF);
checkBox.setText(" Don't remind me next time. ");
checkBox.setScaleX(0.9f);
checkBox.setScaleY(0.9f);
checkBox.setOnCheckedChangeListener((buttonView, isChecked) ->
sharedPreferences.edit().putBoolean("run_anyway", isChecked).apply());
checkboxRow.addView(checkBox);
checkboxRow.setGravity(Gravity.CENTER);
int[] colors = {Color.TRANSPARENT, Color.TRANSPARENT};
int[] pressed = {Color.GREEN, Color.GREEN};
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, colors);
gd.setStroke(3, Color.DKGRAY);
gd.setCornerRadius(100);
GradientDrawable gd2 = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, pressed);
gd2.setStroke(3, Color.DKGRAY);
gd2.setCornerRadius(100);
Button button = new Button(getContext());
button.setText("Run Forge..");
button.setTypeface(Typeface.DEFAULT_BOLD);
StateListDrawable states = new StateListDrawable();
states.addState(new int[]{android.R.attr.state_pressed}, gd2);
states.addState(new int[]{}, gd);
button.setBackground(states);
button.setTextColor(Color.RED);
button.setOnClickListener(v -> {
button.setClickable(false);
crossfade(forgeView, TL);
});
buttonRow.addView(button);
buttonRow.setGravity(Gravity.CENTER);
TL.addView(messageRow, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.addView(checkboxRow, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.addView(buttonRow, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.setGravity(Gravity.CENTER);
crossfade(TL, forgeLogo);
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
private AnimatorSet getAnimator(Animator play, Animator with, AnimatorListenerAdapter adapter) {
AnimatorSet animatorSet = new AnimatorSet();
if (with != null)
animatorSet.play(play).with(with);
else
animatorSet.play(play);
animatorSet.addListener(adapter);
return animatorSet;
}
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (Gadapter!=null) if (Gadapter != null)
Gadapter.exit(); Gadapter.exit();
super.onBackPressed(); super.onBackPressed();
} }
private boolean checkPermission() { private boolean checkPermission() {
int pid = android.os.Process.myPid(); int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid(); int uid = android.os.Process.myUid();
try { try {
int result = this.getBaseContext().checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, pid, uid); int result = getBaseContext().checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, pid, uid);
if (result == PackageManager.PERMISSION_GRANTED) { return result == PackageManager.PERMISSION_GRANTED;
return true;
} else {
return false;
}
} catch (NullPointerException e) { } catch (NullPointerException e) {
return false; return false;
} }
} }
private void requestPermission() {
//Show Information about why you need the permission
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Storage Permission Denied...");
builder.setMessage("This app needs storage permission to run properly.\n\n\n\n");
builder.setPositiveButton("Open App Details", (dialog, which) -> {
dialog.cancel();
//ActivityCompat crashes... maybe it needs the appcompat v7???
//ActivityCompat.requestPermissions(Main.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
});
/*builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
} private void initForge(AndroidAdapter adapter, boolean permissiongranted, int totalRAM, boolean isTabletDevice) {
});*/ AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
builder.show(); config.useAccelerometer = false;
} config.useCompass = false;
config.useGyroscope = false;
config.useRotationVectorSensor = false;
config.useImmersiveMode = false;
config.nativeLoader = () -> ReLinker.loadLibrary(getContext(), "gdx");
private void initForge(AndroidAdapter adapter, boolean permissiongranted, int totalRAM, boolean isTabletDevice, int AndroidAPI, String AndroidRelease){
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
//fake init for error message String message = getDeviceName() + "\n" + "Android " + Build.VERSION.RELEASE + "\n" + "RAM " + totalRAM + "MB" + "\n" + "LibGDX " + Version.VERSION + "\n" + "Can't access external storage";
//set current orientation
String message = getDeviceName()+"\n"+"Android "+AndroidRelease+"\n"+"RAM "+ totalRAM+"MB" +"\n"+"LibGDX "+ Version.VERSION+"\n"+"Can't access external storage";
Sentry.addBreadcrumb(new Breadcrumb(message));
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation); Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
initialize(Forge.getApp(getAndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName())); loadGame("", "", false, adapter, permissiongranted, totalRAM, isTabletDevice, config, true, message);
displayMessage(adapter, true, message);
return; return;
} }
String obbforge = Environment.getExternalStorageDirectory() + "/obbforge"; ASSETS_DIR = Build.VERSION.SDK_INT > 29 ? getContext().getObbDir() + "/Forge/" : Environment.getExternalStorageDirectory() + "/Forge/";
//if obbforge file exists in Phone Storage, Forge uses app-specific Obb directory as path, Android 11+ is mandatory even without obbforge if (!FileUtil.ensureDirectoryExists(ASSETS_DIR)) {
String assetsDir = (FileUtil.doesFileExist(obbforge) || Build.VERSION.SDK_INT > 29) ? getContext().getObbDir()+"/Forge/" : Environment.getExternalStorageDirectory()+"/Forge/"; String message = getDeviceName() + "\n" + "Android " + Build.VERSION.RELEASE + "\n" + "RAM " + totalRAM + "MB" + "\n" + "LibGDX " + Version.VERSION + "\n" + "Can't access external storage\nPath: " + ASSETS_DIR;
if (!FileUtil.ensureDirectoryExists(assetsDir)) {
//fake init for error message
//set current orientation
String message = getDeviceName()+"\n"+"Android "+AndroidRelease+"\n"+"RAM "+ totalRAM+"MB" +"\n"+"LibGDX "+ Version.VERSION+"\n"+"Can't access external storage\nPath: " + assetsDir;
Sentry.addBreadcrumb(new Breadcrumb(message));
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation); Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
initialize(Forge.getApp(getAndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName())); loadGame("", "", false, adapter, permissiongranted, totalRAM, isTabletDevice, config, true, message);
displayMessage(adapter, true, message);
return; return;
} }
boolean isPortrait; //ensure .nomedia file exists in Forge directory so its images
if (permissiongranted) { //and other media files don't appear in Gallery or other apps
//ensure .nomedia file exists in Forge directory so its images String noMediaFile = ASSETS_DIR + ".nomedia";
//and other media files don't appear in Gallery or other apps if (!FileUtil.doesFileExist(noMediaFile)) {
String noMediaFile = assetsDir + ".nomedia"; try {
if (!FileUtil.doesFileExist(noMediaFile)) {
FileUtil.writeFile(noMediaFile, ""); FileUtil.writeFile(noMediaFile, "");
} catch (Exception e) {
String message = getDeviceName() + "\n" + "Android " + Build.VERSION.RELEASE + "\n" + "RAM " + totalRAM + "MB" + "\n" + "LibGDX " + Version.VERSION + "\n" + "Can't read/write to storage";
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
loadGame("", "", false, adapter, permissiongranted, totalRAM, isTabletDevice, config, true, message);
return;
} }
//enforce orientation based on whether device is a tablet and user preference
adapter.switchOrientationFile = assetsDir + "switch_orientation.ini";
boolean landscapeMode = adapter.isTablet == !FileUtil.doesFileExist(adapter.switchOrientationFile);
ForgePreferences prefs = FModel.getPreferences();
boolean propertyConfig = prefs != null && prefs.getPrefBoolean(ForgePreferences.FPref.UI_NETPLAY_COMPAT);
if (landscapeMode) {
isPortrait = false;
Main.this.setRequestedOrientation(Build.VERSION.SDK_INT >= 26 ?
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE : //Oreo and above has virtual back/menu buttons
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
isPortrait = true;
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
initialize(Forge.getApp(getAndroidClipboard(), adapter, assetsDir, propertyConfig, isPortrait, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName()));
} else {
isPortrait = true;
//fake init for permission instruction
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
initialize(Forge.getApp(getAndroidClipboard(), adapter, "", false, isPortrait, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName()));
displayMessage(adapter, false, "");
} }
//enforce orientation based on whether device is a tablet and user preference
adapter.switchOrientationFile = ASSETS_DIR + "switch_orientation.ini";
boolean landscapeMode = adapter.isTablet == !FileUtil.doesFileExist(adapter.switchOrientationFile);
String info = totalRAM < 3500 || Build.VERSION.SDK_INT < 29 ? "Device Specification Check\n" + getDeviceName()
+ "\n" + "Android " + Build.VERSION.RELEASE + "\n" + "RAM " + totalRAM + "MB\n\nMinimum Requirements:" : "";
String lowV = Build.VERSION.SDK_INT < 29 ? "\nAPI: Android 10 or higher" : "";
String lowM = totalRAM < 3500 ? "\nRAM: 4GB RAM or higher" : "";
if (landscapeMode && Build.VERSION.SDK_INT > 32) {
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
loadGame(info, lowV + lowM, landscapeMode, adapter, permissiongranted, totalRAM, isTabletDevice, config, false, "");
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
hasLaunched = false;
try {
final Forge forge = (Forge) Gdx.app.getApplicationListener();
if (forge != null)
forge.dispose();
} catch (Exception e) {
e.printStackTrace();
}
super.onDestroy(); super.onDestroy();
//ensure app doesn't stick around //ensure app doesn't stick around
//ActivityManager am = (ActivityManager)getSystemService(Activity.ACTIVITY_SERVICE); //ActivityManager am = (ActivityManager)getSystemService(Activity.ACTIVITY_SERVICE);
@@ -290,8 +461,7 @@ public class Main extends AndroidApplication {
} }
@Override @Override
protected void onPause() protected void onPause() {
{
super.onPause(); super.onPause();
ForgePreferences prefs = FModel.getPreferences(); ForgePreferences prefs = FModel.getPreferences();
@@ -317,8 +487,7 @@ public class Main extends AndroidApplication {
if (cm.getPrimaryClip().getItemCount() > 0) { if (cm.getPrimaryClip().getItemCount() > 0) {
try { try {
return cm.getPrimaryClip().getItemAt(0).coerceToText(getContext()).length() > 0; return cm.getPrimaryClip().getItemAt(0).coerceToText(getContext()).length() > 0;
} } catch (Exception ex) {
catch (Exception ex) {
return false; return false;
} }
} }
@@ -331,8 +500,7 @@ public class Main extends AndroidApplication {
try { try {
String text = cm.getPrimaryClip().getItemAt(0).coerceToText(getContext()).toString(); String text = cm.getPrimaryClip().getItemAt(0).coerceToText(getContext()).toString();
return Normalizer.normalize(text, Normalizer.Form.NFD); return Normalizer.normalize(text, Normalizer.Form.NFD);
} } catch (Exception ex) {
catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
@@ -341,7 +509,11 @@ public class Main extends AndroidApplication {
@Override @Override
public void setContents(String contents0) { public void setContents(String contents0) {
cm.setPrimaryClip(ClipData.newPlainText("Forge", contents0)); try {
cm.setPrimaryClip(ClipData.newPlainText("Forge", contents0));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
} }
@@ -380,16 +552,23 @@ public class Main extends AndroidApplication {
@Override @Override
public boolean openFile(String filename) { public boolean openFile(String filename) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //ensure this task isn't linked to this application Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(filename)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //ensure this task isn't linked to this application
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension( Uri uri = Uri.fromFile(new File(filename));
MimeTypeMap.getFileExtensionFromUrl(uri.toString())); String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
intent.setDataAndType(uri, type); MimeTypeMap.getFileExtensionFromUrl(uri.toString()));
startActivity(intent); intent.setDataAndType(uri, type);
return true; startActivity(intent);
} return true;
catch (Exception e) { } else {
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(PublicFileProvider.getUriForFile(getContext(), "com.mydomain.publicfileprovider", new File(filename)));
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
return true;
}
} catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return false; return false;
@@ -397,28 +576,7 @@ public class Main extends AndroidApplication {
@Override @Override
public void restart() { public void restart() {
try { //solution from http://stackoverflow.com/questions/6609414/howto-programatically-restart-android-app triggerRebirth();
Context c = getApplicationContext();
PackageManager pm = c.getPackageManager();
if (pm != null) {
//create the intent with the default start activity for your application
Intent mStartActivity = pm.getLaunchIntentForPackage(c.getPackageName());
if (mStartActivity != null) {
mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//create a pending intent so the application is restarted after System.exit(0) was called.
// We use an AlarmManager to call this intent in 100ms
int mPendingIntentId = 223344;
PendingIntent mPendingIntent = PendingIntent.getActivity(c, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
//kill the application
System.exit(0);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
} }
@Override @Override
@@ -439,8 +597,7 @@ public class Main extends AndroidApplication {
//create file to indicate that portrait mode should be used for tablet or landscape should be used for phone //create file to indicate that portrait mode should be used for tablet or landscape should be used for phone
if (landscapeMode != isTablet) { if (landscapeMode != isTablet) {
FileUtil.writeFile(switchOrientationFile, "1"); FileUtil.writeFile(switchOrientationFile, "1");
} } else {
else {
FileUtil.deleteFile(switchOrientationFile); FileUtil.deleteFile(switchOrientationFile);
} }
} }
@@ -450,14 +607,7 @@ public class Main extends AndroidApplication {
// Setting getWindow() Flags needs to run on UI thread. // Setting getWindow() Flags needs to run on UI thread.
// Should fix android.view.ViewRoot$CalledFromWrongThreadException: // Should fix android.view.ViewRoot$CalledFromWrongThreadException:
// Only the original thread that created a view hierarchy can touch its views. // Only the original thread that created a view hierarchy can touch its views.
runOnUiThread(() -> { preventSleep(preventSleep);
if (preventSleep) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
});
} }
@Override @Override
@@ -465,6 +615,7 @@ public class Main extends AndroidApplication {
Bitmap bmp = BitmapFactory.decodeStream(input); Bitmap bmp = BitmapFactory.decodeStream(input);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, output); bmp.compress(Bitmap.CompressFormat.JPEG, 100, output);
} }
@Override @Override
public Pair<Integer, Integer> getRealScreenSize(boolean real) { public Pair<Integer, Integer> getRealScreenSize(boolean real) {
//app size //app size
@@ -473,12 +624,12 @@ public class Main extends AndroidApplication {
Point size = new Point(); Point size = new Point();
if (Build.VERSION.SDK_INT >= 17) { if (Build.VERSION.SDK_INT >= 17) {
// Seems it doesn't compile if using 4.1.1.4 since it's missing this method // Seems it doesn't compile if using 4.1.1.4 since it's missing this method
/*if (real) if (real)
display.getRealSize(size); display.getRealSize(size);
else else
display.getSize(size);*/ display.getSize(size);
//remove this line below and use the method above if using Android libs higher than 4.1.1.4 //remove this line below and use the method above if using Android libs higher than 4.1.1.4
return Pair.of(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); // this method don't take account the soft navigation bars taken in rendered screen //return Pair.of(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); // this method don't take account the soft navigation bars taken in rendered screen
} else if (Build.VERSION.SDK_INT >= 14) { } else if (Build.VERSION.SDK_INT >= 14) {
try { try {
size.x = (Integer) Display.class.getMethod("getRawWidth").invoke(display); size.x = (Integer) Display.class.getMethod("getRawWidth").invoke(display);
@@ -499,13 +650,42 @@ public class Main extends AndroidApplication {
return gamepads; return gamepads;
} }
} }
private void preventSleep(boolean preventSleep) {
runOnUiThread(() -> {
if (preventSleep) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} else {
if (!isMIUI)
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
});
}
private void triggerRebirth() {
try {
Context context = getApplicationContext();
PackageManager packageManager = context.getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
ComponentName componentName = intent.getComponent();
Intent mainIntent = Intent.makeRestartActivityTask(componentName);
// Required for API 34 and later
// Ref: https://developer.android.com/about/versions/14/behavior-changes-14#safer-intents
mainIntent.setPackage(context.getPackageName());
context.startActivity(mainIntent);
Runtime.getRuntime().exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
private ArrayList<String> getGameControllers() { private ArrayList<String> getGameControllers() {
ArrayList<String> gameControllerDeviceIds = new ArrayList<String>(); ArrayList<String> gameControllerDeviceIds = new ArrayList<>();
int[] deviceIds = InputDevice.getDeviceIds(); int[] deviceIds = InputDevice.getDeviceIds();
for (int deviceId : deviceIds) { for (int deviceId : deviceIds) {
InputDevice dev = InputDevice.getDevice(deviceId); InputDevice dev = InputDevice.getDevice(deviceId);
int sources = dev.getSources(); int sources = dev.getSources();
String devNameId = dev.getName()+"["+deviceId+"]"; String devNameId = dev.getName() + "[" + deviceId + "]";
// Verify that the device has gamepad buttons, control sticks, or both. // Verify that the device has gamepad buttons, control sticks, or both.
if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
@@ -522,7 +702,7 @@ public class Main extends AndroidApplication {
public String getDeviceName() { public String getDeviceName() {
String manufacturer = Build.MANUFACTURER; String manufacturer = Build.MANUFACTURER;
String model = Build.MODEL; String model = Build.BRAND + " - " + Build.MODEL;
if (model.toLowerCase().startsWith(manufacturer.toLowerCase())) { if (model.toLowerCase().startsWith(manufacturer.toLowerCase())) {
return capitalize(model); return capitalize(model);
} else { } else {

View File

@@ -68,7 +68,7 @@
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-robovm</artifactId> <artifactId>gdx-backend-robovm</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -20,6 +20,7 @@
<include>**/*.vert</include> <include>**/*.vert</include>
<include>**/*.frag</include> <include>**/*.frag</include>
<include>**/title_bg_lq.png</include> <include>**/title_bg_lq.png</include>
<include>**/title_bg_lq_portrait.png</include>
<include>**/transition.png</include> <include>**/transition.png</include>
<include>**/adv_bg_texture.jpg</include> <include>**/adv_bg_texture.jpg</include>
<include>**/adv_bg_splash.png</include> <include>**/adv_bg_splash.png</include>
@@ -216,12 +217,6 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>forge</groupId> <groupId>forge</groupId>
@@ -231,18 +226,18 @@
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-lwjgl3</artifactId> <artifactId>gdx-backend-lwjgl3</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-platform</artifactId> <artifactId>gdx-platform</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<classifier>natives-desktop</classifier> <classifier>natives-desktop</classifier>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-freetype-platform</artifactId> <artifactId>gdx-freetype-platform</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<classifier>natives-desktop</classifier> <classifier>natives-desktop</classifier>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli --> <!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
@@ -254,12 +249,18 @@
<dependency> <dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId> <groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-desktop</artifactId> <artifactId>gdx-controllers-desktop</artifactId>
<version>2.2.3-SNAPSHOT</version> <version>2.2.3</version>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-box2d-platform</artifactId> <artifactId>gdx-box2d-platform</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
<classifier>natives-desktop</classifier> <classifier>natives-desktop</classifier>
</dependency> </dependency>
</dependencies> </dependencies>

Binary file not shown.

View File

@@ -24,10 +24,6 @@
</plugins> </plugins>
</build> </build>
<repositories> <repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
<repository> <repository>
<id>jitpack.io</id> <id>jitpack.io</id>
<url>https://jitpack.io</url> <url>https://jitpack.io</url>
@@ -58,37 +54,61 @@
<groupId>com.github.tommyettinger</groupId> <groupId>com.github.tommyettinger</groupId>
<artifactId>textratypist</artifactId> <artifactId>textratypist</artifactId>
<version>0.8.2</version> <version>0.8.2</version>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId> <groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-core</artifactId> <artifactId>gdx-controllers-core</artifactId>
<version>2.2.3-SNAPSHOT</version> <version>2.2.3</version>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId> <artifactId>gdx</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-freetype</artifactId> <artifactId>gdx-freetype</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.raeleus.TenPatch</groupId> <groupId>com.github.raeleus.TenPatch</groupId>
<artifactId>tenpatch</artifactId> <artifactId>tenpatch</artifactId>
<version>5.2.3</version> <version>5.2.3</version>
<scope>compile</scope> <scope>compile</scope>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-box2d</artifactId> <artifactId>gdx-box2d</artifactId>
<version>1.11.0</version> <version>1.12.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx</groupId> <groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-ai</artifactId> <artifactId>gdx-ai</artifactId>
<version>1.8.2</version> <version>1.8.2</version>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -23,6 +23,11 @@ public abstract class HudScene extends Scene implements InputProcessor, IAfterMa
hud = GameHUD.getInstance(); hud = GameHUD.getInstance();
} }
@Override
public boolean touchCancelled (int x, int y, int pointer, int button) {
return touchUp(x, y, pointer, button);
}
@Override @Override
public void connected(final Controller controller) { public void connected(final Controller controller) {
hud.ui.controllerConnected(); hud.ui.controllerConnected();

View File

@@ -52,26 +52,15 @@ public class AssetsDownloader {
"You are currently on an older version (" + Forge.CURRENT_VERSION + ").\n\n" + "You are currently on an older version (" + Forge.CURRENT_VERSION + ").\n\n" +
"Would you like to update to the new version now?"; "Would you like to update to the new version now?";
if (!Forge.getDeviceAdapter().isConnectedToWifi()) { if (!Forge.getDeviceAdapter().isConnectedToWifi()) {
message += " If so, you may want to connect to wifi first. The download is around 6.5MB."; message += " If so, you may want to connect to wifi first. The download is around 12MB.";
} }
if (SOptionPane.showConfirmDialog(message, "New Version Available", "Update Now", "Update Later", true, true)) { if (SOptionPane.showConfirmDialog(message, "New Version Available", "Update Now", "Update Later", true, true)) {
String apkFile = new GuiDownloadZipService("", "update", apkURL, String apkFile = new GuiDownloadZipService("", "update", apkURL,
Forge.getDeviceAdapter().getDownloadsDir(), null, splashScreen.getProgressBar()).download(filename); Forge.getDeviceAdapter().getDownloadsDir(), null, splashScreen.getProgressBar()).download(filename);
if (apkFile != null) { if (apkFile != null) {
/* FileUriExposedException was added on API 24, Forge now targets API 26 so Android 10 and above runs, Forge.getDeviceAdapter().openFile(apkFile);
most user thinks Forge crashes but in reality, the method below just can't open the apk when Forge Forge.isMobileAdventureMode = Forge.advStartup;
exits silently to run the downloaded apk. Some devices allow the apk to run but most users are annoyed when Forge.exitAnimation(false);
Forge didn't open the apk so I downgrade the check so it will run only on target devices without FileUriExposedException */
if (Forge.androidVersion < 24) {
Forge.getDeviceAdapter().openFile(apkFile);
Forge.exitAnimation(false);
return;
}
// API 24 and above needs manual apk installation unless we provide a FileProvider for FileUriExposedException
switch (SOptionPane.showOptionDialog("Download Successful. Go to your downloads folder and install " + filename +" to update Forge. Forge will now exit.", "", null, ImmutableList.of("Ok"))) {
default:
Forge.exitAnimation(false);
}
return; return;
} }
SOptionPane.showOptionDialog("Could not download update. " + SOptionPane.showOptionDialog("Could not download update. " +