fix crashes caused by opening settings

This commit is contained in:
izzy2lost
2025-10-14 14:44:06 -04:00
parent ff88f5d573
commit 9a38c38ef0
6 changed files with 320 additions and 83 deletions
@@ -45,6 +45,16 @@ public class GameSettingsDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
// Pause game when game settings dialog is shown
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && !NativeApp.isPaused()) {
NativeApp.pause();
}
}
} catch (Throwable ignored) {}
Context ctx = requireContext();
View view = getLayoutInflater().inflate(R.layout.dialog_game_settings, null, false);
@@ -371,7 +381,21 @@ public class GameSettingsDialogFragment extends DialogFragment {
});
}
return builder.create();
Dialog dialog = builder.create();
// Resume game when dialog is dismissed
dialog.setOnDismissListener(d -> {
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && NativeApp.isPaused()) {
NativeApp.resume();
}
}
} catch (Throwable ignored) {}
});
return dialog;
}
private void saveGameSettings(String gameSerial, String gameCrc,
@@ -117,10 +117,33 @@ public class GamesCoverDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
// Pause game when games cover dialog is shown
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && !NativeApp.isPaused()) {
NativeApp.pause();
}
}
} catch (Throwable ignored) {}
// Return a styled dialog; content is provided by onCreateView
Dialog d = new Dialog(requireContext(), R.style.PSX2_FullScreenDialog);
// Ensure immersive as soon as window exists
try { applyImmersiveToWindow(d.getWindow()); } catch (Throwable ignored) {}
// Resume game when dialog is dismissed
d.setOnDismissListener(dialog -> {
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && NativeApp.isPaused()) {
NativeApp.resume();
}
}
} catch (Throwable ignored) {}
});
return d;
}
@@ -100,6 +100,11 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
return false;
}
// Public method to check if emulation thread is running
public boolean isEmulationThreadRunning() {
return isThread();
}
// Expose whether a game has been chosen (non-empty path)
public boolean hasSelectedGame() {
return !TextUtils.isEmpty(m_szGamefile);
@@ -496,6 +501,9 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Setup right drawer quick actions
setupRightDrawerActions();
// Setup drawer listeners for pause/resume
setupDrawerListeners();
// Setup picture-in-picture support
addPictureInPictureSupport();
}
@@ -545,11 +553,34 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
if (btn_settings != null) {
btn_settings.setOnClickListener(v -> {
try {
// Refresh drawer settings before opening
refreshDrawerSettings();
// Pause game when opening settings drawer
if (hasSelectedGame() && isThread() && !NativeApp.isPaused()) {
NativeApp.pause();
}
// Get drawer layout first
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer != null) drawer.openDrawer(androidx.core.view.GravityCompat.START);
} catch (Throwable ignored) {}
if (drawer != null) {
// Refresh drawer settings before opening - add error handling
try {
refreshDrawerSettings();
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing drawer settings: " + e.getMessage());
// Continue anyway even if refresh fails
}
drawer.openDrawer(androidx.core.view.GravityCompat.START);
}
} catch (Throwable t) {
android.util.Log.e("MainActivity", "Error opening settings drawer: " + t.getMessage());
// Try to open drawer directly as fallback
try {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer != null) {
drawer.openDrawer(androidx.core.view.GravityCompat.START);
}
} catch (Throwable fallback) {
android.util.Log.e("MainActivity", "Fallback drawer open also failed: " + fallback.getMessage());
}
}
});
}
@@ -1968,71 +1999,133 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
private void refreshDrawerSettings() {
try {
NavigationView nav = findViewById(R.id.nav_view);
if (nav != null && nav.getHeaderCount() > 0) {
View header = nav.getHeaderView(0);
if (header != null) {
SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
// Refresh spinner values to reflect current settings
Spinner spAspect = header.findViewById(R.id.drawer_sp_aspect_ratio);
if (spAspect != null && spAspect.getAdapter() != null) {
int savedAspect = prefs.getInt("aspect_ratio", 1);
ArrayAdapter<?> aspectAdapter = (ArrayAdapter<?>) spAspect.getAdapter();
if (savedAspect >= 0 && savedAspect < aspectAdapter.getCount()) {
spAspect.setSelection(savedAspect);
}
}
Spinner spScale = header.findViewById(R.id.drawer_sp_scale);
if (spScale != null && spScale.getAdapter() != null) {
float savedScale = prefs.getFloat("upscale_multiplier", 1.0f);
ArrayAdapter<?> scaleAdapter = (ArrayAdapter<?>) spScale.getAdapter();
int scaleIndex = Math.max(0, Math.min(scaleAdapter.getCount() - 1, Math.round(savedScale) - 1));
spScale.setSelection(scaleIndex);
}
Spinner spBlending = header.findViewById(R.id.drawer_sp_blending_accuracy);
if (spBlending != null && spBlending.getAdapter() != null) {
int savedBlend = prefs.getInt("blending_accuracy", 1);
ArrayAdapter<?> blendAdapter = (ArrayAdapter<?>) spBlending.getAdapter();
if (savedBlend >= 0 && savedBlend < blendAdapter.getCount()) {
spBlending.setSelection(savedBlend);
}
}
// Refresh switch states
com.google.android.material.materialswitch.MaterialSwitch swWide = header.findViewById(R.id.drawer_sw_widescreen);
if (swWide != null) {
swWide.setChecked(prefs.getBoolean("widescreen_patches", true));
}
com.google.android.material.materialswitch.MaterialSwitch swNoInt = header.findViewById(R.id.drawer_sw_no_interlacing);
if (swNoInt != null) {
swNoInt.setChecked(prefs.getBoolean("no_interlacing_patches", true));
}
com.google.android.material.materialswitch.MaterialSwitch swLoadTex = header.findViewById(R.id.drawer_sw_load_textures);
if (swLoadTex != null) {
swLoadTex.setChecked(prefs.getBoolean("load_textures", false));
}
com.google.android.material.materialswitch.MaterialSwitch swAsyncTex = header.findViewById(R.id.drawer_sw_async_textures);
if (swAsyncTex != null) {
swAsyncTex.setChecked(prefs.getBoolean("async_texture_loading", true));
}
com.google.android.material.materialswitch.MaterialSwitch swPrecache = header.findViewById(R.id.drawer_sw_precache_textures);
if (swPrecache != null) {
swPrecache.setChecked(prefs.getBoolean("precache_textures", false));
}
com.google.android.material.materialswitch.MaterialSwitch swDevHud = header.findViewById(R.id.drawer_sw_dev_hud);
if (swDevHud != null) {
swDevHud.setChecked(prefs.getBoolean("hud_visible", false));
if (nav == null) {
android.util.Log.w("MainActivity", "NavigationView not found during refreshDrawerSettings");
return;
}
// Ensure header exists before trying to access it
if (nav.getHeaderCount() == 0) {
android.util.Log.w("MainActivity", "NavigationView has no header during refreshDrawerSettings");
return;
}
View header = nav.getHeaderView(0);
if (header == null) {
android.util.Log.w("MainActivity", "NavigationView header is null during refreshDrawerSettings");
return;
}
SharedPreferences prefs = null;
try {
prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error getting SharedPreferences: " + e.getMessage());
return;
}
if (prefs == null) {
android.util.Log.e("MainActivity", "SharedPreferences is null during refreshDrawerSettings");
return;
}
// Refresh spinner values to reflect current settings
try {
Spinner spAspect = header.findViewById(R.id.drawer_sp_aspect_ratio);
if (spAspect != null && spAspect.getAdapter() != null) {
int savedAspect = prefs.getInt("aspect_ratio", 1);
ArrayAdapter<?> aspectAdapter = (ArrayAdapter<?>) spAspect.getAdapter();
if (savedAspect >= 0 && savedAspect < aspectAdapter.getCount()) {
spAspect.setSelection(savedAspect);
}
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing aspect ratio spinner: " + e.getMessage());
}
} catch (Throwable ignored) {}
try {
Spinner spScale = header.findViewById(R.id.drawer_sp_scale);
if (spScale != null && spScale.getAdapter() != null) {
float savedScale = prefs.getFloat("upscale_multiplier", 1.0f);
ArrayAdapter<?> scaleAdapter = (ArrayAdapter<?>) spScale.getAdapter();
int scaleIndex = Math.max(0, Math.min(scaleAdapter.getCount() - 1, Math.round(savedScale) - 1));
spScale.setSelection(scaleIndex);
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing scale spinner: " + e.getMessage());
}
try {
Spinner spBlending = header.findViewById(R.id.drawer_sp_blending_accuracy);
if (spBlending != null && spBlending.getAdapter() != null) {
int savedBlend = prefs.getInt("blending_accuracy", 1);
ArrayAdapter<?> blendAdapter = (ArrayAdapter<?>) spBlending.getAdapter();
if (savedBlend >= 0 && savedBlend < blendAdapter.getCount()) {
spBlending.setSelection(savedBlend);
}
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing blending spinner: " + e.getMessage());
}
// Refresh switch states with individual error handling
try {
com.google.android.material.materialswitch.MaterialSwitch swWide = header.findViewById(R.id.drawer_sw_widescreen);
if (swWide != null) {
swWide.setChecked(prefs.getBoolean("widescreen_patches", true));
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing widescreen switch: " + e.getMessage());
}
try {
com.google.android.material.materialswitch.MaterialSwitch swNoInt = header.findViewById(R.id.drawer_sw_no_interlacing);
if (swNoInt != null) {
swNoInt.setChecked(prefs.getBoolean("no_interlacing_patches", true));
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing no interlacing switch: " + e.getMessage());
}
try {
com.google.android.material.materialswitch.MaterialSwitch swLoadTex = header.findViewById(R.id.drawer_sw_load_textures);
if (swLoadTex != null) {
swLoadTex.setChecked(prefs.getBoolean("load_textures", false));
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing load textures switch: " + e.getMessage());
}
try {
com.google.android.material.materialswitch.MaterialSwitch swAsyncTex = header.findViewById(R.id.drawer_sw_async_textures);
if (swAsyncTex != null) {
swAsyncTex.setChecked(prefs.getBoolean("async_texture_loading", true));
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing async textures switch: " + e.getMessage());
}
try {
com.google.android.material.materialswitch.MaterialSwitch swPrecache = header.findViewById(R.id.drawer_sw_precache_textures);
if (swPrecache != null) {
swPrecache.setChecked(prefs.getBoolean("precache_textures", false));
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing precache textures switch: " + e.getMessage());
}
try {
com.google.android.material.materialswitch.MaterialSwitch swDevHud = header.findViewById(R.id.drawer_sw_dev_hud);
if (swDevHud != null) {
swDevHud.setChecked(prefs.getBoolean("hud_visible", false));
}
} catch (Exception e) {
android.util.Log.e("MainActivity", "Error refreshing dev HUD switch: " + e.getMessage());
}
} catch (Throwable t) {
android.util.Log.e("MainActivity", "Unexpected error in refreshDrawerSettings: " + t.getMessage());
}
}
private void loadAndApplyStoredSettings() {
@@ -2204,6 +2297,41 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
.show();
}
private void setupDrawerListeners() {
try {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer != null) {
drawer.addDrawerListener(new androidx.drawerlayout.widget.DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {}
@Override
public void onDrawerOpened(@NonNull View drawerView) {
// Pause game when any drawer is opened
try {
if (hasSelectedGame() && isThread() && !NativeApp.isPaused()) {
NativeApp.pause();
}
} catch (Throwable ignored) {}
}
@Override
public void onDrawerClosed(@NonNull View drawerView) {
// Resume game when all drawers are closed
try {
if (hasSelectedGame() && isThread() && NativeApp.isPaused()) {
NativeApp.resume();
}
} catch (Throwable ignored) {}
}
@Override
public void onDrawerStateChanged(int newState) {}
});
}
} catch (Throwable ignored) {}
}
private void setupRightDrawerActions() {
try {
View rightDrawer = findViewById(R.id.end_drawer);
@@ -2251,7 +2379,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
// Exit Game button (pause + open games)
// Exit Game button (open games dialog)
View btnExitGame = rightDrawer.findViewById(R.id.right_drawer_btn_exit_game);
if (btnExitGame != null) {
btnExitGame.setOnClickListener(v -> {
@@ -2259,9 +2387,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Close right drawer first
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer != null) drawer.closeDrawer(androidx.core.view.GravityCompat.END);
// Pause the game first
togglePauseState();
// Then open games dialog after a short delay
// Open games dialog after a short delay
findViewById(android.R.id.content).postDelayed(() -> {
openGamesDialog();
}, 300);
@@ -21,6 +21,16 @@ public class QuickActionsDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
// Pause game when quick actions dialog is shown
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && !NativeApp.isPaused()) {
NativeApp.pause();
}
}
} catch (Throwable ignored) {}
View view = getLayoutInflater().inflate(R.layout.dialog_quick_actions, null, false);
FloatingActionButton btnPower = view.findViewById(R.id.btn_quick_power);
@@ -232,21 +242,13 @@ public class QuickActionsDialogFragment extends DialogFragment {
});
}
// Exit Game: pause game and open games dialog
// Exit Game: open games dialog
if (btnExitGame != null) {
btnExitGame.setOnClickListener(v -> {
try {
// Capture a stable Activity reference before dismissing the dialog
final android.app.Activity activity = getActivity();
// Pause the game first (toggle like the drawer action)
if (activity instanceof MainActivity) {
((MainActivity) activity).togglePauseState();
} else {
boolean paused = NativeApp.isPaused();
if (!paused) NativeApp.pause();
}
// Close this dialog
dismissAllowingStateLoss();
@@ -270,10 +272,24 @@ public class QuickActionsDialogFragment extends DialogFragment {
// Cancel button
if (btnCancel != null) btnCancel.setOnClickListener(v -> dismissAllowingStateLoss());
return new MaterialAlertDialogBuilder(requireContext(),
Dialog dialog = new MaterialAlertDialogBuilder(requireContext(),
com.google.android.material.R.style.ThemeOverlay_Material3_MaterialAlertDialog)
.setView(view)
.create();
// Resume game when dialog is dismissed
dialog.setOnDismissListener(d -> {
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && NativeApp.isPaused()) {
NativeApp.resume();
}
}
} catch (Throwable ignored) {}
});
return dialog;
}
private void quitApp() {
@@ -148,6 +148,16 @@ public class SavesDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
// Pause game when saves dialog is shown
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && !NativeApp.isPaused()) {
NativeApp.pause();
}
}
} catch (Throwable ignored) {}
Context ctx = requireContext();
View view = getLayoutInflater().inflate(R.layout.dialog_saves, null, false);
@@ -203,6 +213,20 @@ public class SavesDialogFragment extends DialogFragment {
.setView(view)
.setNegativeButton("Cancel", (d, w) -> d.dismiss());
return builder.create();
Dialog dialog = builder.create();
// Resume game when dialog is dismissed
dialog.setOnDismissListener(d -> {
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && NativeApp.isPaused()) {
NativeApp.resume();
}
}
} catch (Throwable ignored) {}
});
return dialog;
}
}
@@ -72,6 +72,16 @@ public class SettingsDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
// Pause game when settings dialog is shown
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && !NativeApp.isPaused()) {
NativeApp.pause();
}
}
} catch (Throwable ignored) {}
Context ctx = requireContext();
View view = getLayoutInflater().inflate(R.layout.dialog_settings, null, false);
@@ -280,7 +290,21 @@ public class SettingsDialogFragment extends DialogFragment {
} catch (Throwable ignored) {}
});
return b.create();
Dialog dialog = b.create();
// Resume game when dialog is dismissed
dialog.setOnDismissListener(d -> {
try {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity.hasSelectedGame() && mainActivity.isEmulationThreadRunning() && NativeApp.isPaused()) {
NativeApp.resume();
}
}
} catch (Throwable ignored) {}
});
return dialog;
}
private static int scaleToIndex(float scale) {