Browse Source

Save the settings in more cases to avoid losing setting changes (especially on Android) (#14266)

grorp 3 months ago
parent
commit
a29d3cf074

+ 11 - 0
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

+ 16 - 0
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

+ 21 - 4
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()

+ 7 - 0
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 <sstream>
 #include <exception>
@@ -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();