From d4f47c2a5558480dafcc7078a4ab81d2d2e8c44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Tue, 16 Jul 2024 12:34:19 +0200 Subject: [PATCH] Implement client restarting on Android Restarting the client previously did not work, as the `shell_execute` function on Android uses `fork` which is not supported. Now, the client is restarted by using an Android intent to restart the main activity. This is triggered by sending a user-defined message from the native code to the SDL main activity thread. --- .../java/org/ddnet/client/NativeMain.java | 23 +++++++++++++++++++ src/android/android_main.cpp | 9 ++++++++ src/android/android_main.h | 8 +++++++ src/engine/client/client.cpp | 6 +++++ 4 files changed, 46 insertions(+) diff --git a/scripts/android/files/java/org/ddnet/client/NativeMain.java b/scripts/android/files/java/org/ddnet/client/NativeMain.java index 646ccb509..a3d6400f8 100644 --- a/scripts/android/files/java/org/ddnet/client/NativeMain.java +++ b/scripts/android/files/java/org/ddnet/client/NativeMain.java @@ -3,10 +3,13 @@ package org.ddnet.client; import android.app.NativeActivity; import org.libsdl.app.SDLActivity; import android.os.Bundle; +import android.content.Intent; import android.content.pm.ActivityInfo; public class NativeMain extends SDLActivity { + private static final int COMMAND_RESTART_APP = SDLActivity.COMMAND_USER + 1; + @Override protected String[] getLibraries() { return new String[] { @@ -19,4 +22,24 @@ public class NativeMain extends SDLActivity { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); super.onCreate(SavedInstanceState); } + + @Override + protected boolean onUnhandledMessage(int command, Object param) { + if(command == COMMAND_RESTART_APP) { + restartApp(); + return true; + } + return false; + } + + private void restartApp() { + Intent restartIntent = + Intent.makeRestartActivityTask( + getPackageManager().getLaunchIntentForPackage( + getPackageName() + ).getComponent() + ); + restartIntent.setPackage(getPackageName()); + startActivity(restartIntent); + } } diff --git a/src/android/android_main.cpp b/src/android/android_main.cpp index 558c130d0..e60ec4976 100644 --- a/src/android/android_main.cpp +++ b/src/android/android_main.cpp @@ -225,3 +225,12 @@ const char *InitAndroid() return nullptr; } + +// See NativeMain.java +constexpr uint32_t COMMAND_USER = 0x8000; +constexpr uint32_t COMMAND_RESTART_APP = COMMAND_USER + 1; + +void RestartAndroidApp() +{ + SDL_AndroidSendMessage(COMMAND_RESTART_APP, 0); +} diff --git a/src/android/android_main.h b/src/android/android_main.h index 29a2ee402..c7e3a3e88 100644 --- a/src/android/android_main.h +++ b/src/android/android_main.h @@ -20,4 +20,12 @@ */ const char *InitAndroid(); +/** + * Sends an intent to the Android system to restart the app. + * + * This will restart the main activity in a new task. The current process + * must immediately terminate after this function is called. + */ +void RestartAndroidApp(); + #endif // ANDROID_ANDROID_MAIN_H diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 00b60790b..d343c0436 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -4594,11 +4594,13 @@ int main(int argc, const char **argv) pClient->Run(); const bool Restarting = pClient->State() == CClient::STATE_RESTARTING; +#if !defined(CONF_PLATFORM_ANDROID) char aRestartBinaryPath[IO_MAX_PATH_LENGTH]; if(Restarting) { pStorage->GetBinaryPath(PLAT_CLIENT_EXEC, aRestartBinaryPath, sizeof(aRestartBinaryPath)); } +#endif std::vector vQuittingWarnings = pClient->QuittingWarnings(); @@ -4611,7 +4613,11 @@ int main(int argc, const char **argv) if(Restarting) { +#if defined(CONF_PLATFORM_ANDROID) + RestartAndroidApp(); +#else shell_execute(aRestartBinaryPath, EShellExecuteWindowState::FOREGROUND); +#endif } PerformFinalCleanup();