diff --git a/forge-adventure/pom.xml b/forge-adventure/pom.xml index 9677ab11dc4..e460df493c5 100644 --- a/forge-adventure/pom.xml +++ b/forge-adventure/pom.xml @@ -12,8 +12,11 @@ Forge Adventure - gdx-nightlies - https://oss.sonatype.org/content/repositories/snapshots/ + 4thline-repo + http://4thline.org/m2 + + false + jitpack.io @@ -29,6 +32,7 @@ **/*.vert **/*.frag **/title_bg_lq.png + **/title_bg_lq_portrait.png **/transition.png **/adv_bg_texture.jpg **/adv_bg_splash.png @@ -231,36 +235,36 @@ com.badlogicgames.gdx gdx - 1.11.0 + 1.12.1 compile com.badlogicgames.gdx gdx-platform - 1.11.0 + 1.12.1 natives-desktop com.badlogicgames.gdx gdx-freetype - 1.11.0 + 1.12.1 com.badlogicgames.gdx gdx-backend-lwjgl - 1.11.0 + 1.12.1 compile com.badlogicgames.gdx gdx-tools - 1.11.0 + 1.12.1 compile com.badlogicgames.gdx gdx-freetype-platform - 1.11.0 + 1.12.1 natives-desktop @@ -287,7 +291,13 @@ com.badlogicgames.gdx-controllers gdx-controllers-desktop - 2.2.3-SNAPSHOT + 2.2.3 + + + com.badlogicgames.gdx + gdx + + diff --git a/forge-core/pom.xml b/forge-core/pom.xml index a9bfc658a86..14c1dcef60f 100644 --- a/forge-core/pom.xml +++ b/forge-core/pom.xml @@ -16,7 +16,7 @@ com.google.guava guava - 32.0.0-android + 33.2.1-android org.apache.commons diff --git a/forge-gui-android/AndroidManifest.xml b/forge-gui-android/AndroidManifest.xml index 3e10e483e4e..2e6e5308476 100644 --- a/forge-gui-android/AndroidManifest.xml +++ b/forge-gui-android/AndroidManifest.xml @@ -5,10 +5,11 @@ android:versionName="1.6.64" > + android:minSdkVersion="26" + android:targetSdkVersion="28" /> + @@ -24,17 +25,9 @@ android:label="@string/app_name" android:largeHeap="true"> - - + android:name=".Launcher" + android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode" + android:theme="@style/Theme.Transparent"> @@ -45,8 +38,26 @@ + + - + + + + + + + + + + + + + + + + diff --git a/forge-gui-android/filters/build.txt b/forge-gui-android/filters/build.txt new file mode 100644 index 00000000000..aca99ef22d7 --- /dev/null +++ b/forge-gui-android/filters/build.txt @@ -0,0 +1 @@ +${timestamp} \ No newline at end of file diff --git a/forge-gui-android/libs/arm64-v8a/libgdx-box2d.so b/forge-gui-android/libs/arm64-v8a/libgdx-box2d.so index e562acc0b86..f3a8a41cdcc 100644 Binary files a/forge-gui-android/libs/arm64-v8a/libgdx-box2d.so and b/forge-gui-android/libs/arm64-v8a/libgdx-box2d.so differ diff --git a/forge-gui-android/libs/arm64-v8a/libgdx-freetype.so b/forge-gui-android/libs/arm64-v8a/libgdx-freetype.so index df49aac07f3..9f7e218abc9 100644 Binary files a/forge-gui-android/libs/arm64-v8a/libgdx-freetype.so and b/forge-gui-android/libs/arm64-v8a/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/arm64-v8a/libgdx.so b/forge-gui-android/libs/arm64-v8a/libgdx.so index 74e129d29f2..ffb154277e7 100644 Binary files a/forge-gui-android/libs/arm64-v8a/libgdx.so and b/forge-gui-android/libs/arm64-v8a/libgdx.so differ diff --git a/forge-gui-android/libs/armeabi-v7a/libgdx-box2d.so b/forge-gui-android/libs/armeabi-v7a/libgdx-box2d.so index eef089879ed..00700e9d50c 100644 Binary files a/forge-gui-android/libs/armeabi-v7a/libgdx-box2d.so and b/forge-gui-android/libs/armeabi-v7a/libgdx-box2d.so differ diff --git a/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so b/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so index 922f56bccea..6ceab900ad0 100644 Binary files a/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so and b/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/armeabi-v7a/libgdx.so b/forge-gui-android/libs/armeabi-v7a/libgdx.so index 83c72a3395f..7192dc626f0 100644 Binary files a/forge-gui-android/libs/armeabi-v7a/libgdx.so and b/forge-gui-android/libs/armeabi-v7a/libgdx.so differ diff --git a/forge-gui-android/libs/gdx-backend-android-sources.jar b/forge-gui-android/libs/gdx-backend-android-sources.jar index c44e7889e7d..524836a1f35 100644 Binary files a/forge-gui-android/libs/gdx-backend-android-sources.jar and b/forge-gui-android/libs/gdx-backend-android-sources.jar differ diff --git a/forge-gui-android/libs/gdx-backend-android.jar b/forge-gui-android/libs/gdx-backend-android.jar index 528dde1cfe6..f67fc316ccd 100644 Binary files a/forge-gui-android/libs/gdx-backend-android.jar and b/forge-gui-android/libs/gdx-backend-android.jar differ diff --git a/forge-gui-android/libs/gdx-freetype.jar b/forge-gui-android/libs/gdx-freetype.jar index b0c5060437f..7882e998dda 100644 Binary files a/forge-gui-android/libs/gdx-freetype.jar and b/forge-gui-android/libs/gdx-freetype.jar differ diff --git a/forge-gui-android/libs/gdx-sources.jar b/forge-gui-android/libs/gdx-sources.jar index 22d94b50342..85793e30966 100644 Binary files a/forge-gui-android/libs/gdx-sources.jar and b/forge-gui-android/libs/gdx-sources.jar differ diff --git a/forge-gui-android/libs/gdx.jar b/forge-gui-android/libs/gdx.jar index 1a0381b8566..cca18342888 100644 Binary files a/forge-gui-android/libs/gdx.jar and b/forge-gui-android/libs/gdx.jar differ diff --git a/forge-gui-android/libs/publicfileprovider.jar b/forge-gui-android/libs/publicfileprovider.jar new file mode 100644 index 00000000000..6ede1654e9b Binary files /dev/null and b/forge-gui-android/libs/publicfileprovider.jar differ diff --git a/forge-gui-android/libs/relinker.jar b/forge-gui-android/libs/relinker.jar new file mode 100644 index 00000000000..22fc82b4b09 Binary files /dev/null and b/forge-gui-android/libs/relinker.jar differ diff --git a/forge-gui-android/libs/x86/libgdx-box2d.so b/forge-gui-android/libs/x86/libgdx-box2d.so index df1fef60837..98a5aefa823 100644 Binary files a/forge-gui-android/libs/x86/libgdx-box2d.so and b/forge-gui-android/libs/x86/libgdx-box2d.so differ diff --git a/forge-gui-android/libs/x86/libgdx-freetype.so b/forge-gui-android/libs/x86/libgdx-freetype.so index e2cd515dbe1..b98bf59da7b 100644 Binary files a/forge-gui-android/libs/x86/libgdx-freetype.so and b/forge-gui-android/libs/x86/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/x86/libgdx.so b/forge-gui-android/libs/x86/libgdx.so index f9e1e416fd1..623b66290d5 100644 Binary files a/forge-gui-android/libs/x86/libgdx.so and b/forge-gui-android/libs/x86/libgdx.so differ diff --git a/forge-gui-android/libs/x86_64/libgdx-box2d.so b/forge-gui-android/libs/x86_64/libgdx-box2d.so index 852d26455f4..6d8d101fb9b 100644 Binary files a/forge-gui-android/libs/x86_64/libgdx-box2d.so and b/forge-gui-android/libs/x86_64/libgdx-box2d.so differ diff --git a/forge-gui-android/libs/x86_64/libgdx-freetype.so b/forge-gui-android/libs/x86_64/libgdx-freetype.so index 67c46fe75a6..b71ab3b08f0 100644 Binary files a/forge-gui-android/libs/x86_64/libgdx-freetype.so and b/forge-gui-android/libs/x86_64/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/x86_64/libgdx.so b/forge-gui-android/libs/x86_64/libgdx.so index 0f8457506b5..87a2ca594ed 100644 Binary files a/forge-gui-android/libs/x86_64/libgdx.so and b/forge-gui-android/libs/x86_64/libgdx.so differ diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml index 0c5ee1e7e22..3e078f2dbed 100644 --- a/forge-gui-android/pom.xml +++ b/forge-gui-android/pom.xml @@ -2,7 +2,8 @@ 4.0.0 - yyyyMMdd-HHmm + ${maven.build.timestamp} + yyyy-MM-dd HH:mm:ss jar -Xms1024m -Xmx1536m @@ -26,6 +27,13 @@ ${packaging.type} Forge Android + + + Google Maven + https://maven.google.com/ + + + src @@ -45,30 +53,44 @@ forge-android-${alpha-version} - - - gdx-nightlies - https://oss.sonatype.org/content/repositories/snapshots/ - - - com.google.android - android - 4.1.1.4 + org.robolectric + android-all + 8.0.0_r4-robolectric-0 provided + + de.cketti.fileprovider + public-fileprovider + 1.0.0 + system + ${pom.basedir}/libs/publicfileprovider.jar + + + com.getkeepsafe.relinker + relinker + 1.4.5 + system + ${pom.basedir}/libs/relinker.jar + org.apache.httpcomponents httpclient - 4.5.13 + 4.5.14 + + + commons-codec + commons-codec + + commons-codec commons-codec - 1.15 + 1.16.0 forge @@ -104,7 +126,9 @@ com.badlogicgames.gdx gdx-backend-android - 1.11.0 + 1.12.1 + system + ${pom.basedir}/libs/gdx-backend-android.jar io.sentry @@ -176,8 +200,14 @@ com.badlogicgames.gdx-controllers gdx-controllers-android - 2.2.3-SNAPSHOT + 2.2.3 aar + + + com.badlogicgames.gdx + gdx-backend-android + + @@ -423,6 +453,11 @@ + + + + + diff --git a/forge-gui-android/proguard.cfg b/forge-gui-android/proguard.cfg index 35c2b4eae3d..b4cc8fcab34 100644 --- a/forge-gui-android/proguard.cfg +++ b/forge-gui-android/proguard.cfg @@ -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 /jmods/java.base.jmod(!**.jar;!module-info.class) +##-libraryjars /jmods/java.datatransfer.jmod(!**.jar;!module-info.class) +##-libraryjars /jmods/java.prefs.jmod(!**.jar;!module-info.class) +##-libraryjars /jmods/java.xml.jmod(!**.jar;!module-info.class) +##-libraryjars /jmods/java.desktop.jmod(!**.jar;!module-info.class) ##-libraryjars /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.** { *; } diff --git a/forge-gui-android/res/drawable/bg_gradient.xml b/forge-gui-android/res/drawable/bg_gradient.xml new file mode 100644 index 00000000000..a040e21cd84 --- /dev/null +++ b/forge-gui-android/res/drawable/bg_gradient.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/forge-gui-android/res/drawable/logo.png b/forge-gui-android/res/drawable/logo.png new file mode 100644 index 00000000000..71598bc678d Binary files /dev/null and b/forge-gui-android/res/drawable/logo.png differ diff --git a/forge-gui-android/res/drawable/splash_background.xml b/forge-gui-android/res/drawable/splash_background.xml new file mode 100644 index 00000000000..8b82397d93e --- /dev/null +++ b/forge-gui-android/res/drawable/splash_background.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/forge-gui-android/res/layout/main.xml b/forge-gui-android/res/layout/main.xml index 777a3e48e4e..b074850f1e5 100644 --- a/forge-gui-android/res/layout/main.xml +++ b/forge-gui-android/res/layout/main.xml @@ -1,7 +1,38 @@ - + - \ No newline at end of file + + + + + + \ No newline at end of file diff --git a/forge-gui-android/res/layout/splash.xml b/forge-gui-android/res/layout/splash.xml new file mode 100644 index 00000000000..ab8302b1005 --- /dev/null +++ b/forge-gui-android/res/layout/splash.xml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/forge-gui-android/res/values-w820dp/dimens.xml b/forge-gui-android/res/values-w820dp/dimens.xml new file mode 100644 index 00000000000..63fc8164446 --- /dev/null +++ b/forge-gui-android/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/forge-gui-android/res/values/colors.xml b/forge-gui-android/res/values/colors.xml new file mode 100644 index 00000000000..c33b8418321 --- /dev/null +++ b/forge-gui-android/res/values/colors.xml @@ -0,0 +1,8 @@ + + + #3F51B5 + #303F9F + #FF4081 + #258cec + #000000 + diff --git a/forge-gui-android/res/values/dimens.xml b/forge-gui-android/res/values/dimens.xml new file mode 100644 index 00000000000..47c82246738 --- /dev/null +++ b/forge-gui-android/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/forge-gui-android/res/values/styles.xml b/forge-gui-android/res/values/styles.xml new file mode 100644 index 00000000000..90ec268463f --- /dev/null +++ b/forge-gui-android/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/forge-gui-android/res/values/themes.xml b/forge-gui-android/res/values/themes.xml new file mode 100644 index 00000000000..226e82a0912 --- /dev/null +++ b/forge-gui-android/res/values/themes.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/forge-gui-android/res/xml/publicfileprovider_paths.xml b/forge-gui-android/res/xml/publicfileprovider_paths.xml new file mode 100644 index 00000000000..c589ed2ebc7 --- /dev/null +++ b/forge-gui-android/res/xml/publicfileprovider_paths.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/forge-gui-android/src/forge/app/Launcher.java b/forge-gui-android/src/forge/app/Launcher.java index 84dabfd9797..701d91f90d4 100644 --- a/forge-gui-android/src/forge/app/Launcher.java +++ b/forge-gui-android/src/forge/app/Launcher.java @@ -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) { diff --git a/forge-gui-android/src/forge/app/Main.java b/forge-gui-android/src/forge/app/Main.java index 166c282da3c..1562937d252 100644 --- a/forge-gui-android/src/forge/app/Main.java +++ b/forge-gui-android/src/forge/app/Main.java @@ -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 gamepads; - AndroidClipboard androidClipboard; - boolean hasLaunched; + private AndroidAdapter Gadapter; + private ArrayList 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); @@ -89,51 +151,84 @@ public class Main extends AndroidApplication { actManager.getMemoryInfo(memInfo); 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); + boolean permissiongranted = checkPermission(); + 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(); + Display display = ((Activity) activityContext).getWindowManager().getDefaultDisplay(); DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); 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 false; + return diagonalInches >= 7.0; } - 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); - startActivity(intent); + 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); } + + 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 public void onBackPressed() { - if (Gadapter!=null) + 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 = this.getBaseContext().checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, pid, uid); - if (result == PackageManager.PERMISSION_GRANTED) { - return true; - } else { - return false; - } + int result = getBaseContext().checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, pid, uid); + return result == PackageManager.PERMISSION_GRANTED; } 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() { - @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) { + 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"); - 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)); + 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); - initialize(Forge.getApp(getAndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName())); - displayMessage(adapter, true, message); + loadGame("", "", false, adapter, permissiongranted, totalRAM, isTabletDevice, config, 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)); + 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); - initialize(Forge.getApp(getAndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName())); - displayMessage(adapter, true, message); + loadGame("", "", false, adapter, permissiongranted, totalRAM, isTabletDevice, config, 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)) { + //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 = 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 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) { - 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 public boolean openFile(String filename) { try { - 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)); - String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension( - MimeTypeMap.getFileExtensionFromUrl(uri.toString())); - intent.setDataAndType(uri, type); - startActivity(intent); - return true; - } - catch (Exception e) { + 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)); + String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension( + MimeTypeMap.getFileExtensionFromUrl(uri.toString())); + 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) { 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 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 getGameControllers() { - ArrayList gameControllerDeviceIds = new ArrayList(); + ArrayList 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 { diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml index 8753cfeb158..ec789a767fc 100644 --- a/forge-gui-ios/pom.xml +++ b/forge-gui-ios/pom.xml @@ -68,7 +68,7 @@ com.badlogicgames.gdx gdx-backend-robovm - 1.11.0 + 1.12.1 diff --git a/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar b/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar index 8fbd0cb3813..0485da75bac 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar and b/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar differ diff --git a/forge-gui-mobile-dev/libs/gdx-box2d-platform-natives.jar b/forge-gui-mobile-dev/libs/gdx-box2d-platform-natives.jar index d2f8f105679..b8c835fd2c2 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-box2d-platform-natives.jar and b/forge-gui-mobile-dev/libs/gdx-box2d-platform-natives.jar differ diff --git a/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar b/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar index 87ceb2eb26e..564d2f5139e 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar and b/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar differ diff --git a/forge-gui-mobile-dev/libs/gdx-natives.jar b/forge-gui-mobile-dev/libs/gdx-natives.jar index 10d0a113c8a..fb8b5e13ec2 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-natives.jar and b/forge-gui-mobile-dev/libs/gdx-natives.jar differ diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml index 7694be00a9b..26e8304d334 100644 --- a/forge-gui-mobile-dev/pom.xml +++ b/forge-gui-mobile-dev/pom.xml @@ -20,6 +20,7 @@ **/*.vert **/*.frag **/title_bg_lq.png + **/title_bg_lq_portrait.png **/transition.png **/adv_bg_texture.jpg **/adv_bg_splash.png @@ -216,12 +217,6 @@ - - - gdx-nightlies - https://oss.sonatype.org/content/repositories/snapshots/ - - forge @@ -231,18 +226,18 @@ com.badlogicgames.gdx gdx-backend-lwjgl3 - 1.11.0 + 1.12.1 com.badlogicgames.gdx gdx-platform - 1.11.0 + 1.12.1 natives-desktop com.badlogicgames.gdx gdx-freetype-platform - 1.11.0 + 1.12.1 natives-desktop @@ -254,12 +249,18 @@ com.badlogicgames.gdx-controllers gdx-controllers-desktop - 2.2.3-SNAPSHOT + 2.2.3 + + + com.badlogicgames.gdx + gdx + + com.badlogicgames.gdx gdx-box2d-platform - 1.11.0 + 1.12.1 natives-desktop diff --git a/forge-gui-mobile/libs/gdx-freetype.jar b/forge-gui-mobile/libs/gdx-freetype.jar index b0c5060437f..7882e998dda 100644 Binary files a/forge-gui-mobile/libs/gdx-freetype.jar and b/forge-gui-mobile/libs/gdx-freetype.jar differ diff --git a/forge-gui-mobile/libs/gdx-sources.jar b/forge-gui-mobile/libs/gdx-sources.jar index 22d94b50342..85793e30966 100644 Binary files a/forge-gui-mobile/libs/gdx-sources.jar and b/forge-gui-mobile/libs/gdx-sources.jar differ diff --git a/forge-gui-mobile/libs/gdx.jar b/forge-gui-mobile/libs/gdx.jar index 1a0381b8566..cca18342888 100644 Binary files a/forge-gui-mobile/libs/gdx.jar and b/forge-gui-mobile/libs/gdx.jar differ diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index ecb25e59aa0..91cc8d9f6a5 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -24,10 +24,6 @@ - - gdx-nightlies - https://oss.sonatype.org/content/repositories/snapshots/ - jitpack.io https://jitpack.io @@ -58,37 +54,61 @@ com.github.tommyettinger textratypist 0.8.2 + + + com.badlogicgames.gdx + gdx + + com.badlogicgames.gdx-controllers gdx-controllers-core - 2.2.3-SNAPSHOT + 2.2.3 + + + com.badlogicgames.gdx + gdx + + com.badlogicgames.gdx gdx - 1.11.0 + 1.12.1 com.badlogicgames.gdx gdx-freetype - 1.11.0 + 1.12.1 com.github.raeleus.TenPatch tenpatch 5.2.3 compile + + + com.badlogicgames.gdx + gdx + + com.badlogicgames.gdx gdx-box2d - 1.11.0 + 1.12.1 com.badlogicgames.gdx gdx-ai 1.8.2 + + + com.badlogicgames.gdx + gdx + + diff --git a/forge-gui-mobile/src/forge/adventure/scene/HudScene.java b/forge-gui-mobile/src/forge/adventure/scene/HudScene.java index 639e1a0242b..79312c2fc66 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/HudScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/HudScene.java @@ -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(); diff --git a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java index 09acca91f4c..6663ae926ff 100644 --- a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java +++ b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java @@ -52,26 +52,15 @@ 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.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); - } + Forge.getDeviceAdapter().openFile(apkFile); + Forge.isMobileAdventureMode = Forge.advStartup; + Forge.exitAnimation(false); return; } SOptionPane.showOptionDialog("Could not download update. " +