From a29d3cf074578b70dbc70704616f2b2535f7d2bd Mon Sep 17 00:00:00 2001 From: grorp Date: Tue, 23 Jan 2024 21:33:27 +0100 Subject: [PATCH] Save the settings in more cases to avoid losing setting changes (especially on Android) (#14266) --- .../net/minetest/minetest/GameActivity.java | 11 ++++++++ builtin/mainmenu/settings/dlg_settings.lua | 16 ++++++++++++ src/client/clientlauncher.cpp | 25 ++++++++++++++++--- src/porting_android.cpp | 7 ++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/net/minetest/minetest/GameActivity.java b/android/app/src/main/java/net/minetest/minetest/GameActivity.java index f2ff09f3d..85336ac7e 100644 --- a/android/app/src/main/java/net/minetest/minetest/GameActivity.java +++ b/android/app/src/main/java/net/minetest/minetest/GameActivity.java @@ -85,6 +85,17 @@ public class GameActivity extends NativeActivity { makeFullScreen(); } + private native void saveSettings(); + + @Override + protected void onStop() { + super.onStop(); + // Avoid losing setting changes in case the app is onDestroy()ed later. + // Saving stuff in onStop() is recommended in the Android activity + // lifecycle documentation. + saveSettings(); + } + @Override public void onBackPressed() { // Ignore the back press so Minetest can handle it diff --git a/builtin/mainmenu/settings/dlg_settings.lua b/builtin/mainmenu/settings/dlg_settings.lua index e953c7688..9e5d2a46c 100644 --- a/builtin/mainmenu/settings/dlg_settings.lua +++ b/builtin/mainmenu/settings/dlg_settings.lua @@ -608,6 +608,16 @@ local function get_formspec(dialogdata) end +-- On Android, closing the app via the "Recents screen" won't result in a clean +-- exit, discarding any setting changes made by the user. +-- To avoid that, we write the settings file in more cases on Android. +function write_settings_early() + if PLATFORM == "Android" then + core.settings:write() + end +end + + local function buttonhandler(this, fields) local dialogdata = this.data dialogdata.leftscroll = core.explode_scrollbar_event(fields.leftscroll).value or dialogdata.leftscroll @@ -622,12 +632,15 @@ local function buttonhandler(this, fields) if fields.show_technical_names ~= nil then local value = core.is_yes(fields.show_technical_names) core.settings:set_bool("show_technical_names", value) + write_settings_early() + return true end if fields.show_advanced ~= nil then local value = core.is_yes(fields.show_advanced) core.settings:set_bool("show_advanced", value) + write_settings_early() local suggested_page_id = update_filtered_pages(dialogdata.query) @@ -672,12 +685,15 @@ local function buttonhandler(this, fields) for i, comp in ipairs(dialogdata.components) do if comp.on_submit and comp:on_submit(fields, this) then + write_settings_early() + -- Clear components so they regenerate dialogdata.components = nil return true end if comp.setting and fields["reset_" .. i] then core.settings:remove(comp.setting.name) + write_settings_early() -- Clear components so they regenerate dialogdata.components = nil diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 93d181082..ddfb4fea6 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -250,11 +250,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) } // Break out of menu-game loop to shut down cleanly - if (!m_rendering_engine->run() || *kill) { - if (!g_settings_path.empty()) - g_settings->updateConfigFile(g_settings_path.c_str()); + if (!m_rendering_engine->run() || *kill) break; - } m_rendering_engine->get_video_driver()->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map")); @@ -299,6 +296,16 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) receiver->m_touchscreengui = NULL; #endif + /* Save the settings when leaving the game. + * This makes sure that setting changes made in-game are persisted even + * in case of a later unclean exit from the mainmenu. + * This is especially useful on Android because closing the app from the + * "Recents screen" results in an unclean exit. + * Caveat: This means that the settings are saved twice when exiting Minetest. + */ + if (!g_settings_path.empty()) + g_settings->updateConfigFile(g_settings_path.c_str()); + // If no main menu, show error and exit if (skip_main_menu) { if (!error_message.empty()) { @@ -562,6 +569,16 @@ void ClientLauncher::main_menu(MainMenuData *menudata) /* leave scene manager in a clean state */ m_rendering_engine->get_scene_manager()->clear(); + + /* Save the settings when leaving the mainmenu. + * This makes sure that setting changes made in the mainmenu are persisted + * even in case of a later unclean exit from the game. + * This is especially useful on Android because closing the app from the + * "Recents screen" results in an unclean exit. + * Caveat: This means that the settings are saved twice when exiting Minetest. + */ + if (!g_settings_path.empty()) + g_settings->updateConfigFile(g_settings_path.c_str()); } void ClientLauncher::speed_tests() diff --git a/src/porting_android.cpp b/src/porting_android.cpp index 43c2cea35..a649751d3 100644 --- a/src/porting_android.cpp +++ b/src/porting_android.cpp @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "config.h" #include "filesys.h" #include "log.h" +#include "settings.h" #include #include @@ -39,6 +40,12 @@ with this program; if not, write to the Free Software Foundation, Inc., extern int main(int argc, char *argv[]); +extern "C" JNIEXPORT void JNICALL +Java_net_minetest_minetest_GameActivity_saveSettings(JNIEnv* env, jobject /* this */) { + if (!g_settings_path.empty()) + g_settings->updateConfigFile(g_settings_path.c_str()); +} + namespace porting { // used here: void cleanupAndroid();