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

View File

@@ -16,7 +16,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.0.0-android</version>
<version>33.2.1-android</version>
</dependency>
<dependency>
<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 -->
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="26" />
android:minSdkVersion="26"
android:targetSdkVersion="28" />
<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.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
@@ -23,18 +24,10 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:largeHeap="true">
<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.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">
android:theme="@style/Theme.Transparent">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -45,8 +38,26 @@
<data android:mimeType="text/plain" />
</intent-filter>
</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.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 -->
<provider
android:name="io.sentry.android.core.SentryInitProvider"
@@ -57,5 +68,15 @@
android:authorities=".SentryPerformanceProvider"
android:initOrder="200"
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>
</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>
<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>
<build.min.memory>-Xms1024m</build.min.memory>
<build.max.memory>-Xmx1536m</build.max.memory>
@@ -26,6 +27,13 @@
<packaging>${packaging.type}</packaging>
<name>Forge Android</name>
<repositories>
<repository>
<id>Google Maven</id>
<url>https://maven.google.com/</url>
</repository>
</repositories>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
@@ -45,30 +53,44 @@
</resources>
<finalName>forge-android-${alpha-version}</finalName>
</build>
<repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>4.1.1.4</version>
<groupId>org.robolectric</groupId>
<artifactId>android-all</artifactId>
<version>8.0.0_r4-robolectric-0</version>
<scope>provided</scope>
</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 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<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>
<!-- declare a specific dependency to override org.apache.httpcomponents's transitive dependency -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
<version>1.16.0</version>
</dependency>
<dependency>
<groupId>forge</groupId>
@@ -104,7 +126,9 @@
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<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>
<groupId>io.sentry</groupId>
@@ -176,8 +200,14 @@
<dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-android</artifactId>
<version>2.2.3-SNAPSHOT</version>
<version>2.2.3</version>
<type>aar</type>
<exclusions>
<exclusion>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-android</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
@@ -423,6 +453,11 @@
<exclude name="res/cardsfolder/**" />
</fileset>
</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" />
<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" />

View File

@@ -4,12 +4,16 @@
-dontskipnonpubliclibraryclasses
-dontpreverify
-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
## and spits out a thousand-something Class Not Found errors
##-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.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)
-dontwarn afu.org.checkerframework.**
@@ -57,18 +61,20 @@
-keep class org.apache.commons.lang3.** { *; }
-keep class com.google.guava.** { *; }
-keep class com.google.common.** { *; }
-keep class com.google.gson.GsonBuilder
-keep class io.sentry.event.Event { *; }
-keep class io.sentry.android.core.SentryAndroidOptions
-keep class io.sentry.android.core.SentryAndroid
#-keep class com.google.gson.GsonBuilder
##-keep class io.sentry.event.Event { *; }
##-keep class io.sentry.android.core.SentryAndroidOptions
##-keep class io.sentry.android.core.SentryAndroid
-keep class io.sentry.android.core.SentryInitProvider
-keep class io.sentry.android.core.SentryPerformanceProvider
##-keep class io.sentry.android.core.SentryInitProvider
##-keep class io.sentry.android.core.SentryPerformanceProvider
-keep class com.badlogic.gdx.controllers.android.AndroidControllers { *; }
-keep class com.github.tommyettinger.textra.** { *; }
-keep class io.sentry.android.ndk.SentryNdk
-keep class io.sentry.Sentry
##-keep class io.sentry.android.ndk.SentryNdk
##-keep class io.sentry.Sentry
-keep class io.sentry.** { *; }
-keepclassmembers enum io.sentry.** { *; }
-keep class io.netty.util.internal.logging.** { *; }
-keep class net.jpountz.** { *; }
-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"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainview"
android:layout_width="match_parent"
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.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import forge.gui.GuiBase;
import java.io.BufferedReader;
@@ -20,9 +21,13 @@ public class Launcher extends Activity {
startActivity(main);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
sendIntent(intent, intent.getAction(), 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) {
final Handler handler = new Handler();
handler.postDelayed(() -> {
@@ -50,9 +55,7 @@ public class Launcher extends Activity {
}
}, 1500);
}
finish();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@@ -61,8 +64,7 @@ public class Launcher extends Activity {
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
final Handler handler = new Handler();
handler.postDelayed(() -> {
new Handler(Looper.getMainLooper()).postDelayed(() -> {
if ("text/plain".equals(type)) {
Uri textUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (textUri != null) {

View File

@@ -1,32 +1,26 @@
package forge.app;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.Normalizer;
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.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
@@ -36,35 +30,57 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Gravity;
import android.view.InputDevice;
import android.view.View;
import android.view.WindowManager;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
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.interfaces.IDeviceAdapter;
import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel;
import forge.util.FileUtil;
import forge.util.ThreadUtil;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
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 {
AndroidAdapter Gadapter;
ArrayList<String> gamepads;
AndroidClipboard androidClipboard;
boolean hasLaunched;
private AndroidAdapter Gadapter;
private ArrayList<String> gamepads;
private AndroidClipboard androidClipboard;
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() {
if (androidClipboard == null)
@@ -72,16 +88,62 @@ public class Main extends AndroidApplication {
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
protected void onCreate(Bundle 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)
return;
hasLaunched = true;
//init Sentry
//SentryAndroid.init(this);
isMIUI = isMiUi();
if (isMIUI)
preventSleep(true);
gamepads = getGameControllers();
//get total device RAM in mb
ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
@@ -90,9 +152,40 @@ public class Main extends AndroidApplication {
int totalMemory = Math.round(memInfo.totalMem / 1024f / 1024f);
boolean permissiongranted = checkPermission();
Gadapter = new AndroidAdapter(this.getContext());
initForge(Gadapter, permissiongranted, totalMemory, isTabletDevice(this.getContext()), Build.VERSION.SDK_INT, Build.VERSION.RELEASE);
Gadapter = new AndroidAdapter(getContext());
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) {
Display display = ((Activity) activityContext).getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
@@ -101,39 +194,41 @@ public class Main extends AndroidApplication {
float widthInches = metrics.widthPixels / metrics.xdpi;
float heightInches = metrics.heightPixels / metrics.ydpi;
double diagonalInches = Math.sqrt(Math.pow(widthInches, 2) + Math.pow(heightInches, 2));
if (diagonalInches >= 7.0) {
return true;
return diagonalInches >= 7.0;
}
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);
TL.setBackgroundResource(android.R.color.black);
TableRow row = new TableRow(this);
TableRow row2 = new TableRow(this);
TextView text = new TextView(this);
text.setGravity(Gravity.LEFT);
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";
String steps = " 1) Tap \"Open App Details\" Button.\n" +
" 2) Tap Permissions\n"+
" 3) Turn on the Storage Permission.\n\n"+
String steps = " 1) Tap \"App Settings\" Button.\n" +
" 2) Tap Permissions\n" +
" 3) Enable the " + SP + ".\n\n" +
"(You can tap anywhere to exit and restart the app)\n\n";
if (ex) {
title = "Forge didn't initialize!\n";
steps = msg + "\n\n";
title = manageApp ? "Forge AutoUpdater Permission...\n" : "Forge didn't initialize!\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);
text.append(ss1);
text.append(steps);
row.addView(text);
row.setGravity(Gravity.CENTER);
int[] colors = {Color.TRANSPARENT,Color.TRANSPARENT};
int[] pressed = {Color.GREEN,Color.GREEN};
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);
@@ -145,21 +240,29 @@ public class Main extends AndroidApplication {
gd2.setCornerRadius(100);
Button button = new Button(this);
button.setText("Open App Details");
button.setText("App Settings");
button.setTypeface(Typeface.DEFAULT_BOLD);
StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed}, gd2);
states.addState(new int[] { }, gd);
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 -> {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
if (manageApp) {
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
.setData(Uri.parse(String.format("package:%s", getPackageName())))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
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);
@@ -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(row2, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.setGravity(Gravity.CENTER);
TL.setOnClickListener(v -> adapter.exit());
setContentView(TL);
TL.setOnClickListener(v -> adapter.restart());
crossfade(TL, previousView);
}
@Override
public void onBackPressed() {
if (Gadapter!=null)
Gadapter.exit();
super.onBackPressed();
}
private boolean checkPermission() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
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 {
int result = this.getBaseContext().checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, pid, uid);
if (result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
} catch (NullPointerException e) {
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() {
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 onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
}
});*/
builder.show();
}
private void initForge(AndroidAdapter adapter, boolean permissiongranted, int totalRAM, boolean isTabletDevice, int AndroidAPI, String AndroidRelease){
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
//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";
Sentry.addBreadcrumb(new Breadcrumb(message));
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
initialize(Forge.getApp(getAndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName()));
displayMessage(adapter, true, message);
return;
}
String obbforge = Environment.getExternalStorageDirectory() + "/obbforge";
//if obbforge file exists in Phone Storage, Forge uses app-specific Obb directory as path, Android 11+ is mandatory even without obbforge
String assetsDir = (FileUtil.doesFileExist(obbforge) || Build.VERSION.SDK_INT > 29) ? getContext().getObbDir()+"/Forge/" : Environment.getExternalStorageDirectory()+"/Forge/";
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);
initialize(Forge.getApp(getAndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName()));
displayMessage(adapter, true, message);
return;
}
boolean isPortrait;
if (permissiongranted) {
//ensure .nomedia file exists in Forge directory so its images
//and other media files don't appear in Gallery or other apps
String noMediaFile = assetsDir + ".nomedia";
if (!FileUtil.doesFileExist(noMediaFile)) {
FileUtil.writeFile(noMediaFile, "");
}
//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;
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 {
isPortrait = true;
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
initialize(Forge.getApp(getAndroidClipboard(), adapter, assetsDir, propertyConfig, isPortrait, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName()));
crossfade(forgeView, forgeLogo);
} 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, "");
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
public void onBackPressed() {
if (Gadapter != null)
Gadapter.exit();
super.onBackPressed();
}
private boolean checkPermission() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
try {
int result = getBaseContext().checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, pid, uid);
return result == PackageManager.PERMISSION_GRANTED;
} catch (NullPointerException e) {
return false;
}
}
private void initForge(AndroidAdapter adapter, boolean permissiongranted, int totalRAM, boolean isTabletDevice) {
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.useAccelerometer = false;
config.useCompass = false;
config.useGyroscope = false;
config.useRotationVectorSensor = false;
config.useImmersiveMode = false;
config.nativeLoader = () -> ReLinker.loadLibrary(getContext(), "gdx");
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
String message = getDeviceName() + "\n" + "Android " + Build.VERSION.RELEASE + "\n" + "RAM " + totalRAM + "MB" + "\n" + "LibGDX " + Version.VERSION + "\n" + "Can't access external storage";
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
loadGame("", "", false, adapter, permissiongranted, totalRAM, isTabletDevice, config, true, message);
return;
}
ASSETS_DIR = Build.VERSION.SDK_INT > 29 ? getContext().getObbDir() + "/Forge/" : Environment.getExternalStorageDirectory() + "/Forge/";
if (!FileUtil.ensureDirectoryExists(ASSETS_DIR)) {
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;
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
loadGame("", "", false, adapter, permissiongranted, totalRAM, isTabletDevice, config, true, message);
return;
}
//ensure .nomedia file exists in Forge directory so its images
//and other media files don't appear in Gallery or other apps
String noMediaFile = ASSETS_DIR + ".nomedia";
if (!FileUtil.doesFileExist(noMediaFile)) {
try {
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 = 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
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();
//ensure app doesn't stick around
//ActivityManager am = (ActivityManager)getSystemService(Activity.ACTIVITY_SERVICE);
@@ -290,8 +461,7 @@ public class Main extends AndroidApplication {
}
@Override
protected void onPause()
{
protected void onPause() {
super.onPause();
ForgePreferences prefs = FModel.getPreferences();
@@ -317,8 +487,7 @@ public class Main extends AndroidApplication {
if (cm.getPrimaryClip().getItemCount() > 0) {
try {
return cm.getPrimaryClip().getItemAt(0).coerceToText(getContext()).length() > 0;
}
catch (Exception ex) {
} catch (Exception ex) {
return false;
}
}
@@ -331,8 +500,7 @@ public class Main extends AndroidApplication {
try {
String text = cm.getPrimaryClip().getItemAt(0).coerceToText(getContext()).toString();
return Normalizer.normalize(text, Normalizer.Form.NFD);
}
catch (Exception ex) {
} catch (Exception ex) {
ex.printStackTrace();
}
}
@@ -341,7 +509,11 @@ public class Main extends AndroidApplication {
@Override
public void setContents(String contents0) {
try {
cm.setPrimaryClip(ClipData.newPlainText("Forge", contents0));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@@ -380,6 +552,7 @@ public class Main extends AndroidApplication {
@Override
public boolean openFile(String filename) {
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //ensure this task isn't linked to this application
Uri uri = Uri.fromFile(new File(filename));
@@ -388,8 +561,14 @@ public class Main extends AndroidApplication {
intent.setDataAndType(uri, type);
startActivity(intent);
return true;
} 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) {
} catch (Exception e) {
e.printStackTrace();
}
return false;
@@ -397,28 +576,7 @@ public class Main extends AndroidApplication {
@Override
public void restart() {
try { //solution from http://stackoverflow.com/questions/6609414/howto-programatically-restart-android-app
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();
}
triggerRebirth();
}
@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
if (landscapeMode != isTablet) {
FileUtil.writeFile(switchOrientationFile, "1");
}
else {
} else {
FileUtil.deleteFile(switchOrientationFile);
}
}
@@ -450,14 +607,7 @@ public class Main extends AndroidApplication {
// Setting getWindow() Flags needs to run on UI thread.
// Should fix android.view.ViewRoot$CalledFromWrongThreadException:
// Only the original thread that created a view hierarchy can touch its views.
runOnUiThread(() -> {
if (preventSleep) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
});
preventSleep(preventSleep);
}
@Override
@@ -465,6 +615,7 @@ public class Main extends AndroidApplication {
Bitmap bmp = BitmapFactory.decodeStream(input);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, output);
}
@Override
public Pair<Integer, Integer> getRealScreenSize(boolean real) {
//app size
@@ -473,12 +624,12 @@ public class Main extends AndroidApplication {
Point size = new Point();
if (Build.VERSION.SDK_INT >= 17) {
// Seems it doesn't compile if using 4.1.1.4 since it's missing this method
/*if (real)
if (real)
display.getRealSize(size);
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
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) {
try {
size.x = (Integer) Display.class.getMethod("getRawWidth").invoke(display);
@@ -499,13 +650,42 @@ public class Main extends AndroidApplication {
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() {
ArrayList<String> gameControllerDeviceIds = new ArrayList<String>();
ArrayList<String> gameControllerDeviceIds = new ArrayList<>();
int[] deviceIds = InputDevice.getDeviceIds();
for (int deviceId : deviceIds) {
InputDevice dev = InputDevice.getDevice(deviceId);
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.
if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
@@ -522,7 +702,7 @@ public class Main extends AndroidApplication {
public String getDeviceName() {
String manufacturer = Build.MANUFACTURER;
String model = Build.MODEL;
String model = Build.BRAND + " - " + Build.MODEL;
if (model.toLowerCase().startsWith(manufacturer.toLowerCase())) {
return capitalize(model);
} else {

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

@@ -52,28 +52,17 @@ public class AssetsDownloader {
"You are currently on an older version (" + Forge.CURRENT_VERSION + ").\n\n" +
"Would you like to update to the new version now?";
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)) {
String apkFile = new GuiDownloadZipService("", "update", apkURL,
Forge.getDeviceAdapter().getDownloadsDir(), null, splashScreen.getProgressBar()).download(filename);
if (apkFile != null) {
/* FileUriExposedException was added on API 24, Forge now targets API 26 so Android 10 and above runs,
most user thinks Forge crashes but in reality, the method below just can't open the apk when Forge
exits silently to run the downloaded apk. Some devices allow the apk to run but most users are annoyed when
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.isMobileAdventureMode = Forge.advStartup;
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;
}
SOptionPane.showOptionDialog("Could not download update. " +
"Press OK to proceed without update.", "Update Failed", null, ImmutableList.of("Ok"));
}