mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Update Mobile Build (#5813)
* LibGDX Update * unused import * disable minimize on screen lock
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
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.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 +28,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 +86,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 +149,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 +238,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 +269,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,11 +459,10 @@ public class Main extends AndroidApplication {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
ForgePreferences prefs = FModel.getPreferences();
|
||||
/*ForgePreferences prefs = FModel.getPreferences();
|
||||
boolean minimizeonScreenLock = prefs != null && prefs.getPrefBoolean(ForgePreferences.FPref.UI_ANDROID_MINIMIZE_ON_SCRLOCK);
|
||||
|
||||
if (minimizeonScreenLock) {
|
||||
@@ -305,7 +473,7 @@ public class Main extends AndroidApplication {
|
||||
this.moveTaskToBack(true);
|
||||
// Minimize the app to the background...
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
//special clipboard that words on Android
|
||||
@@ -317,8 +485,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 +498,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 +507,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 +550,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 +574,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 +595,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 +605,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 +613,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 +622,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 +648,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 +700,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 {
|
||||
|
||||
Reference in New Issue
Block a user