Skip to content

Commit

Permalink
Feat: Handle MainActivity destruction (#4817)
Browse files Browse the repository at this point in the history
* Feat[launcher]: begin implementing MainActivity destruction handling

* Feat[lifecycle]: finalize MainActivity lifecycle awareness implementation

* Clean[dialog]: unified halting LifecycleAwareAlertDialog implementation

* Fix[mainactivity]: comment truncated
  • Loading branch information
artdeell authored Nov 7, 2023
1 parent 682fe04 commit d5f74af
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package net.kdt.pojavlaunch;

import static net.kdt.pojavlaunch.MainActivity.fullyExit;

import android.annotation.SuppressLint;
import android.content.ClipboardManager;
import android.os.Bundle;
Expand Down Expand Up @@ -173,14 +171,10 @@ public boolean onTouch(View v, MotionEvent event) {
openLogOutput(null);
new Thread(() -> {
try {
final int exit = doCustomInstall(runtime, modFile, javaArgs);
Logger.appendToLog(getString(R.string.toast_optifine_success));
if (exit != 0) return;
runOnUiThread(() -> {
Toast.makeText(JavaGUILauncherActivity.this, R.string.toast_optifine_success, Toast.LENGTH_SHORT).show();
fullyExit();
});

// Due to time, the code here became, like, actually useless
// So it was removed
// Tbh this whole class needs a refactor...
doCustomInstall(runtime, modFile, javaArgs);
} catch (Throwable e) {
Logger.appendToLog("Install failed:");
Logger.appendToLog(Log.getStackTraceString(e));
Expand Down Expand Up @@ -287,7 +281,7 @@ public void toggleVirtualMouse(View v) {
Toast.LENGTH_SHORT).show();
}

public int launchJavaRuntime(Runtime runtime, File modFile, String javaArgs) {
public void launchJavaRuntime(Runtime runtime, File modFile, String javaArgs) {
JREUtils.redirectAndPrintJRELog();
try {
List<String> javaArgList = new ArrayList<>();
Expand All @@ -313,18 +307,17 @@ public int launchJavaRuntime(Runtime runtime, File modFile, String javaArgs) {

Logger.appendToLog("Info: Java arguments: " + Arrays.toString(javaArgList.toArray(new String[0])));

return JREUtils.launchJavaVM(this, runtime,null,javaArgList, LauncherPreferences.PREF_CUSTOM_JAVA_ARGS);
JREUtils.launchJavaVM(this, runtime,null,javaArgList, LauncherPreferences.PREF_CUSTOM_JAVA_ARGS);
} catch (Throwable th) {
Tools.showError(this, th, true);
return -1;
}
}



private int doCustomInstall(Runtime runtime, File modFile, String javaArgs) {
private void doCustomInstall(Runtime runtime, File modFile, String javaArgs) {
mSkipDetectMod = true;
return launchJavaRuntime(runtime, modFile, javaArgs);
launchJavaRuntime(runtime, modFile, javaArgs);
}

public void toggleKeyboard(View view) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import com.kdt.mcgui.ProgressLayout;
import com.kdt.mcgui.mcAccountSpinner;

import net.kdt.pojavlaunch.contextexecutor.ContextExecutor;
import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
import net.kdt.pojavlaunch.contracts.OpenDocumentWithExtension;
import net.kdt.pojavlaunch.extra.ExtraConstants;
import net.kdt.pojavlaunch.extra.ExtraCore;
Expand All @@ -40,7 +40,7 @@
import net.kdt.pojavlaunch.services.ProgressServiceKeeper;
import net.kdt.pojavlaunch.tasks.AsyncMinecraftDownloader;
import net.kdt.pojavlaunch.tasks.AsyncVersionList;
import net.kdt.pojavlaunch.tasks.ContextAwareDoneListener;
import net.kdt.pojavlaunch.lifecycle.ContextAwareDoneListener;
import net.kdt.pojavlaunch.utils.NotificationUtils;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.DocumentsContract;
import android.util.Log;
import android.view.KeyEvent;
Expand All @@ -36,10 +39,12 @@
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.drawerlayout.widget.DrawerLayout;

import com.kdt.LoggerView;

import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
import net.kdt.pojavlaunch.customcontrols.ControlButtonMenuListener;
import net.kdt.pojavlaunch.customcontrols.ControlData;
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
Expand All @@ -62,7 +67,7 @@
import java.io.File;
import java.io.IOException;

public class MainActivity extends BaseActivity implements ControlButtonMenuListener, EditorExitable {
public class MainActivity extends BaseActivity implements ControlButtonMenuListener, EditorExitable, ServiceConnection {
public static volatile ClipboardManager GLOBAL_CLIPBOARD;
public static final String INTENT_MINECRAFT_VERSION = "intent_version";

Expand All @@ -84,13 +89,17 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
private AdapterView.OnItemClickListener gameActionClickListener;
public ArrayAdapter<String> ingameControlsEditorArrayAdapter;
public AdapterView.OnItemClickListener ingameControlsEditorListener;
private GameService.LocalBinder mServiceBinder;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
minecraftProfile = LauncherProfiles.getCurrentProfile();
MCOptionUtils.load(Tools.getGameDirPath(minecraftProfile).getAbsolutePath());
GameService.startService(this);

Intent gameServiceIntent = new Intent(this, GameService.class);
// Start the service a bit early
ContextCompat.startForegroundService(this, gameServiceIntent);
initLayout(R.layout.activity_basemain);
CallbackBridge.addGrabListener(touchpad);
CallbackBridge.addGrabListener(minecraftGLView);
Expand Down Expand Up @@ -122,6 +131,12 @@ public void onCreate(Bundle savedInstanceState) {
MCOptionUtils.MCOptionListener optionListener = MCOptionUtils::getMcScale;
MCOptionUtils.addMCOptionListener(optionListener);
mControlLayout.setModifiable(false);

// Set the activity for the executor. Must do this here, or else Tools.showErrorRemote() may not
// execute the correct method
ContextExecutor.setActivity(this);
//Now, attach to the service. The game will only start when this happens, to make sure that we know the right state.
bindService(gameServiceIntent, this, 0);
}

protected void initLayout(int resId) {
Expand Down Expand Up @@ -191,11 +206,9 @@ protected void initLayout(int resId) {

runCraft(finalVersion, mVersionInfo);
}catch (Throwable e){
Tools.showError(getApplicationContext(), e, true);
Tools.showErrorRemote(e);
}
});

minecraftGLView.start();
} catch (Throwable e) {
Tools.showError(this, e, true);
}
Expand Down Expand Up @@ -275,6 +288,7 @@ protected void onDestroy() {
super.onDestroy();
CallbackBridge.removeGrabListener(touchpad);
CallbackBridge.removeGrabListener(minecraftGLView);
ContextExecutor.clearActivity();
}

@Override
Expand Down Expand Up @@ -336,6 +350,8 @@ private void runCraft(String versionId, JMinecraftVersionList.Version version) t
int requiredJavaVersion = 8;
if(version.javaVersion != null) requiredJavaVersion = version.javaVersion.majorVersion;
Tools.launchMinecraft(this, minecraftAccount, minecraftProfile, versionId, requiredJavaVersion);
//Note that we actually stall in the above function, even if the game crashes. But let's be safe.
Tools.runOnUiThread(()-> mServiceBinder.isActive = false);
}

private void printLauncherInfo(String gameVersion, String javaArguments) {
Expand Down Expand Up @@ -609,4 +625,17 @@ public void exitEditor() {
navDrawer.setOnItemClickListener(gameActionClickListener);
isInEditor = false;
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
GameService.LocalBinder localBinder = (GameService.LocalBinder) service;
mServiceBinder = localBinder;
minecraftGLView.start(localBinder.isActive);
localBinder.isActive = true;
}

@Override
public void onServiceDisconnected(ComponentName name) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,17 @@ public MinecraftGLSurface(Context context, AttributeSet attributeSet) {
MCOptionUtils.addMCOptionListener(mGuiScaleListener);
}

/** Initialize the view and all its settings */
public void start(){
/** Initialize the view and all its settings
* @param isAlreadyRunning set to true to tell the view that the game is already running
* (only updates the window without calling the start listener)
*/
public void start(boolean isAlreadyRunning){
if(LauncherPreferences.PREF_USE_ALTERNATE_SURFACE){
SurfaceView surfaceView = new SurfaceView(getContext());
mSurface = surfaceView;

surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
private boolean isCalled = false;
private boolean isCalled = isAlreadyRunning;
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
if(isCalled) {
Expand Down Expand Up @@ -180,7 +183,7 @@ public void surfaceDestroyed(@NonNull SurfaceHolder holder) {}
mSurface = textureView;

textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
private boolean isCalled = false;
private boolean isCalled = isAlreadyRunning;
@Override
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
Surface tSurface = new Surface(surface);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import net.kdt.pojavlaunch.contextexecutor.ContextExecutor;
import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
import net.kdt.pojavlaunch.tasks.AsyncAssetManager;
import net.kdt.pojavlaunch.utils.*;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import net.kdt.pojavlaunch.contextexecutor.ContextExecutorTask;
import net.kdt.pojavlaunch.lifecycle.ContextExecutorTask;
import net.kdt.pojavlaunch.utils.NotificationUtils;

import java.io.Serializable;
Expand Down
31 changes: 16 additions & 15 deletions app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.ProgressDialog;
Expand Down Expand Up @@ -39,6 +38,8 @@

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationManagerCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
Expand All @@ -47,8 +48,9 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import net.kdt.pojavlaunch.contextexecutor.ContextExecutor;
import net.kdt.pojavlaunch.contextexecutor.ContextExecutorTask;
import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
import net.kdt.pojavlaunch.lifecycle.ContextExecutorTask;
import net.kdt.pojavlaunch.lifecycle.LifecycleAwareAlertDialog;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.multirt.Runtime;
import net.kdt.pojavlaunch.plugins.FFmpegPlugin;
Expand Down Expand Up @@ -161,21 +163,18 @@ public static void initContextConstants(Context ctx){
NATIVE_LIB_DIR = ctx.getApplicationInfo().nativeLibraryDir;
}


public static void launchMinecraft(final Activity activity, MinecraftAccount minecraftAccount,
public static void launchMinecraft(final AppCompatActivity activity, MinecraftAccount minecraftAccount,
MinecraftProfile minecraftProfile, String versionId, int versionJavaRequirement) throws Throwable {
int freeDeviceMemory = getFreeDeviceMemory(activity);
if(LauncherPreferences.PREF_RAM_ALLOCATION > freeDeviceMemory) {
Object memoryErrorLock = new Object();
activity.runOnUiThread(() -> {
androidx.appcompat.app.AlertDialog.Builder b = new androidx.appcompat.app.AlertDialog.Builder(activity)
.setMessage(activity.getString(R.string.memory_warning_msg, freeDeviceMemory ,LauncherPreferences.PREF_RAM_ALLOCATION))
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {synchronized(memoryErrorLock){memoryErrorLock.notifyAll();}})
.setOnCancelListener((i) -> {synchronized(memoryErrorLock){memoryErrorLock.notifyAll();}});
b.show();
});
synchronized (memoryErrorLock) {
memoryErrorLock.wait();
LifecycleAwareAlertDialog.DialogCreator dialogCreator = (dialog, builder) ->
builder.setMessage(activity.getString(R.string.memory_warning_msg, freeDeviceMemory, LauncherPreferences.PREF_RAM_ALLOCATION))
.setPositiveButton(android.R.string.ok, (d, w)->{});

if(LifecycleAwareAlertDialog.haltOnDialog(activity.getLifecycle(), activity, dialogCreator)) {
return; // If the dialog's lifecycle has ended, return without
// actually launching the game, thus giving us the opportunity
// to start after the activity is shown again
}
}
Runtime runtime = MultiRTUtils.forceReread(Tools.pickRuntime(minecraftProfile, versionJavaRequirement));
Expand Down Expand Up @@ -216,6 +215,8 @@ public static void launchMinecraft(final Activity activity, MinecraftAccount min
if(Tools.isValidString(minecraftProfile.javaArgs)) args = minecraftProfile.javaArgs;
FFmpegPlugin.discover(activity);
JREUtils.launchJavaVM(activity, runtime, gamedir, javaArgList, args);
// If we returned, this means that the JVM exit dialog has been shown and we don't need to be active anymore.
// We never return otherwise. The process will be killed anyway, and thus we will become inactive
}

public static File getGameDirPath(@NonNull MinecraftProfile minecraftProfile){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package net.kdt.pojavlaunch.tasks;
package net.kdt.pojavlaunch.lifecycle;

import static net.kdt.pojavlaunch.MainActivity.INTENT_MINECRAFT_VERSION;

Expand All @@ -9,9 +9,10 @@
import net.kdt.pojavlaunch.MainActivity;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.contextexecutor.ContextExecutor;
import net.kdt.pojavlaunch.contextexecutor.ContextExecutorTask;
import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
import net.kdt.pojavlaunch.lifecycle.ContextExecutorTask;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
import net.kdt.pojavlaunch.tasks.AsyncMinecraftDownloader;
import net.kdt.pojavlaunch.utils.NotificationUtils;

public class ContextAwareDoneListener implements AsyncMinecraftDownloader.DoneListener, ContextExecutorTask {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package net.kdt.pojavlaunch.contextexecutor;
package net.kdt.pojavlaunch.lifecycle;

import android.app.Activity;
import android.app.Application;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package net.kdt.pojavlaunch.contextexecutor;
package net.kdt.pojavlaunch.lifecycle;

import android.app.Activity;
import android.content.Context;
Expand Down
Loading

0 comments on commit d5f74af

Please sign in to comment.