Fix app breaking retroacheivements crashes

This commit is contained in:
izzy2lost
2025-12-10 17:31:17 -05:00
parent b93163ec22
commit 20bbf4a409
3 changed files with 120 additions and 13 deletions
@@ -233,9 +233,20 @@ public class AchievementsDialogFragment extends DialogFragment {
boolean enabled = mEnabledCheckbox.isChecked();
// Check if we're logged in by checking if we have a saved username
String savedUsername = getPrefs().getString(PREF_USERNAME, "");
// Check if we're logged in by looking at saved token/active client
SharedPreferences prefs = getPrefs();
String savedUsername = prefs.getString(PREF_USERNAME, "");
String savedToken = prefs.getString("token", "");
boolean hasCredentials = !savedUsername.isEmpty();
boolean hasToken = savedToken != null && !savedToken.isEmpty();
boolean isActive = false;
try {
isActive = NativeApp.achievementsIsActive();
} catch (Throwable t) {
android.util.Log.w("Achievements", "Could not query active state: " + t.getMessage());
}
// Treat as logged in only when we actually have a saved token AND the client reports active
boolean loggedIn = hasToken && isActive;
if (mHardcoreModeCheckbox != null) mHardcoreModeCheckbox.setEnabled(enabled);
if (mNotificationsCheckbox != null) mNotificationsCheckbox.setEnabled(enabled);
@@ -243,12 +254,17 @@ public class AchievementsDialogFragment extends DialogFragment {
if (mUsernameEdit != null) mUsernameEdit.setEnabled(enabled);
if (mPasswordEdit != null) mPasswordEdit.setEnabled(enabled);
// Login button: enabled when achievements are enabled
mLoginButton.setEnabled(enabled);
// Login button: enabled when achievements are enabled and no active session/token
mLoginButton.setEnabled(enabled && !loggedIn);
mLoginButton.setVisibility(View.VISIBLE);
if (loggedIn) {
mLoginButton.setText("Logged In");
} else {
mLoginButton.setText("Login");
}
// Logout button: enabled if we have saved credentials
mLogoutButton.setEnabled(enabled && hasCredentials);
// Logout button: enabled if we have anything to clear
mLogoutButton.setEnabled(enabled && (hasCredentials || hasToken || isActive));
mLogoutButton.setVisibility(View.VISIBLE);
// Create account button: always enabled
@@ -312,7 +328,7 @@ public class AchievementsDialogFragment extends DialogFragment {
android.util.Log.d("Achievements", "After login - isActive: " + isActive);
if (isActive) {
Toast.makeText(requireContext(), "Login successful! Token saved for auto-login.", Toast.LENGTH_SHORT).show();
Toast.makeText(requireContext(), "Signed into RetroAchievements.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(requireContext(), "Login may have failed - check logs", Toast.LENGTH_LONG).show();
}
@@ -77,6 +77,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
public static final int ORIENTATION_PORTRAIT = 2;
private String m_szGamefile = "";
private boolean mRaLoginPromptScheduled = false;
private HIDDeviceManager mHIDDeviceManager;
private ControllerInputHandler mControllerInputHandler;
@@ -493,9 +494,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Initialize RetroAchievements
RetroAchievementsManager.initialize(this);
// Load and auto-login with saved credentials if available
NativeApp.loadAndLoginAchievements();
// Initialize controller input handler
mControllerInputHandler = new ControllerInputHandler(this);
@@ -560,6 +558,9 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Setup picture-in-picture support
addPictureInPictureSupport();
// Offer RetroAchievements re-login after a short delay (if previously enabled)
scheduleRetroAchievementsReLoginPrompt();
}
@Override
@@ -716,6 +717,17 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
} catch (Throwable ignored) {}
});
}
View btnAchievements = header.findViewById(R.id.drawer_btn_achievements);
if (btnAchievements != null) {
btnAchievements.setOnClickListener(v -> {
try {
AchievementsDialogFragment.newInstance()
.show(getSupportFragmentManager(), "achievements_dialog");
} catch (Throwable t) {
android.util.Log.e("MainActivity", "Failed to open achievements dialog: " + t.getMessage());
}
});
}
View btnAbout = header.findViewById(R.id.drawer_btn_about);
if (btnAbout != null) {
btnAbout.setOnClickListener(v -> {
@@ -1556,6 +1568,12 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
@Override
protected void onDestroy() {
try {
NativeApp.achievementsLogout();
NativeApp.achievementsShutdown();
} catch (Throwable t) {
android.util.Log.w("MainActivity", "Error shutting down achievements on exit: " + t.getMessage());
}
NativeApp.shutdown();
super.onDestroy();
////
@@ -2827,7 +2845,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Register broadcast receiver for PiP actions
registerPiPBroadcastReceiver();
}
private void registerPiPBroadcastReceiver() {
// Register receiver for PiP remote actions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -2879,4 +2897,71 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
}
}
private void scheduleRetroAchievementsReLoginPrompt() {
if (mRaLoginPromptScheduled) return;
mRaLoginPromptScheduled = true;
SharedPreferences prefs = getSharedPreferences("RetroAchievements", MODE_PRIVATE);
boolean enabled = prefs.getBoolean("enabled", false);
String username = prefs.getString("username", "");
String token = prefs.getString("token", "");
if (!enabled || TextUtils.isEmpty(username) || TextUtils.isEmpty(token)) {
return;
}
View decor = (getWindow() != null) ? getWindow().getDecorView() : null;
if (decor == null) return;
decor.postDelayed(() -> {
if (isFinishing() || isDestroyed()) return;
showRetroAchievementsReLoginDialog(username, token);
}, 5000);
}
private void showRetroAchievementsReLoginDialog(String username, String token) {
try {
new MaterialAlertDialogBuilder(this,
com.google.android.material.R.style.ThemeOverlay_Material3_MaterialAlertDialog)
.setTitle("RetroAchievements")
.setMessage("Sign back in as " + username + "?")
.setNegativeButton("Not now", (d, w) -> clearRetroAchievementsSession())
.setPositiveButton("Sign in", (d, w) -> startRetroAchievementsLogin(username, token))
.show();
} catch (Throwable t) {
android.util.Log.w("MainActivity", "Failed to show RetroAchievements prompt: " + t.getMessage());
}
}
private void startRetroAchievementsLogin(String username, String token) {
new Thread(() -> {
try {
NativeApp.achievementsInitialize();
Thread.sleep(500); // let init settle before logging in
NativeApp.achievementsLoginWithToken(username, token);
android.util.Log.i("MainActivity", "RetroAchievements token login started for " + username);
} catch (Throwable t) {
android.util.Log.e("MainActivity", "RetroAchievements token login failed: " + t.getMessage());
}
}).start();
}
private void clearRetroAchievementsSession() {
try {
NativeApp.achievementsLogout();
} catch (Throwable t) {
android.util.Log.w("MainActivity", "RA logout error: " + t.getMessage());
}
try {
SharedPreferences prefs = getSharedPreferences("RetroAchievements", MODE_PRIVATE);
prefs.edit()
.remove("token")
.remove("login_timestamp")
.remove("saved_password")
.putBoolean("remember_me", false)
.apply();
} catch (Throwable t) {
android.util.Log.w("MainActivity", "RA prefs clear error: " + t.getMessage());
}
}
}
@@ -212,6 +212,10 @@ public class NativeApp {
android.util.Log.e("Achievements", "Cannot load credentials: context is null");
return;
}
if (hasNoNativeBinary) {
android.util.Log.w("Achievements", "Skipping auto-login: native core not loaded");
return;
}
android.content.SharedPreferences prefs = context.getSharedPreferences("RetroAchievements", Context.MODE_PRIVATE);
boolean enabled = prefs.getBoolean("enabled", false);
@@ -238,8 +242,10 @@ public class NativeApp {
Thread.sleep(500); // Give it time to initialize
achievementsLoginWithToken(username, token);
android.util.Log.i("Achievements", "Auto-login initiated");
} catch (Exception e) {
android.util.Log.e("Achievements", "Auto-login failed: " + e.getMessage());
} catch (Throwable e) {
android.util.Log.e("Achievements", "Auto-login failed", e);
// Avoid startup crash loops by disabling auto-login until the user re-enables it manually
prefs.edit().putBoolean("enabled", false).apply();
}
}).start();
}