forked from ddnet/ddnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support running local server on Android
Compile the server as a separate library for Android same as the client. Use a foreground service to run the native `main` function of the server using Java Native Interface. Directly using JNI avoids the use of SDL as a wrapper for the server. The server service must run in a different process because it needs to be terminated to correctly restart the server. Otherwise it crashes because global variables are not initialized again when it is restarted. This also prevents simply running the server in another thread of the client process. A toast error message is shown on non-zero return values of server's `main` function. A foreground service is used so the server can keep running while the client activity is in the background. Add detailed description why the service uses `android:foregroundServiceType="specialUse"` in the manifest as this should convince the reviewer that the use case is valid. None of the other foreground service types cover hosting local game servers or related use cases. The required permissions for using a foreground service with special use case are added as well as the permission to post notifications. Showing a notification is necessary for foreground services to stay alive and it also allows showing the server status and controlling the server. In particular, an action to directly stop the server is shown. Another action to run commands based on user input in the notification is provided, which allows setting the initial rcon password. The server will also be stopped automatically if the client is quit or if the server notification is deleted (which is possible on newer Android versions that do not allow ongoing notifications anymore). Rename `NativeMain.java` to `ClientActivity.java` to differentiate the file better from the server class.
- Loading branch information
Showing
17 changed files
with
761 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
scripts/android/files/java/org/ddnet/client/ClientActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package org.ddnet.client; | ||
|
||
import android.app.NativeActivity; | ||
import android.content.*; | ||
import android.content.pm.ActivityInfo; | ||
import android.os.*; | ||
|
||
import androidx.core.content.ContextCompat; | ||
|
||
import org.libsdl.app.SDLActivity; | ||
|
||
public class ClientActivity extends SDLActivity { | ||
|
||
private static final int COMMAND_RESTART_APP = SDLActivity.COMMAND_USER + 1; | ||
|
||
private String[] launchArguments = new String[0]; | ||
|
||
private final Object serverServiceMonitor = new Object(); | ||
private Messenger serverServiceMessenger = null; | ||
private final ServiceConnection serverServiceConnection = new ServiceConnection() { | ||
@Override | ||
public void onServiceConnected(ComponentName name, IBinder service) { | ||
synchronized(serverServiceMonitor) { | ||
serverServiceMessenger = new Messenger(service); | ||
} | ||
} | ||
|
||
@Override | ||
public void onServiceDisconnected(ComponentName name) { | ||
synchronized(serverServiceMonitor) { | ||
serverServiceMessenger = null; | ||
} | ||
} | ||
}; | ||
|
||
@Override | ||
protected String[] getLibraries() { | ||
return new String[] { | ||
"DDNet", | ||
}; | ||
} | ||
|
||
@Override | ||
public void onCreate(Bundle savedInstanceState) { | ||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); | ||
|
||
Intent intent = getIntent(); | ||
if(intent != null) { | ||
String gfxBackend = intent.getStringExtra("gfx-backend"); | ||
if(gfxBackend != null) { | ||
if(gfxBackend.equals("Vulkan")) { | ||
launchArguments = new String[] {"gfx_backend Vulkan"}; | ||
} else if(gfxBackend.equals("GLES")) { | ||
launchArguments = new String[] {"gfx_backend GLES"}; | ||
} | ||
} | ||
} | ||
|
||
super.onCreate(savedInstanceState); | ||
} | ||
|
||
@Override | ||
protected void onDestroy() { | ||
super.onDestroy(); | ||
synchronized(serverServiceMonitor) { | ||
if(serverServiceMessenger != null) { | ||
unbindService(serverServiceConnection); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
protected String[] getArguments() { | ||
return launchArguments; | ||
} | ||
|
||
@Override | ||
protected boolean onUnhandledMessage(int command, Object param) { | ||
switch(command) { | ||
case COMMAND_RESTART_APP: | ||
restartApp(); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
private void restartApp() { | ||
Intent restartIntent = | ||
Intent.makeRestartActivityTask( | ||
getPackageManager().getLaunchIntentForPackage( | ||
getPackageName() | ||
).getComponent() | ||
); | ||
restartIntent.setPackage(getPackageName()); | ||
startActivity(restartIntent); | ||
} | ||
|
||
// Called from native code, see android_main.cpp | ||
public void startServer() { | ||
synchronized(serverServiceMonitor) { | ||
if(serverServiceMessenger != null) { | ||
return; | ||
} | ||
Intent startIntent = new Intent(this, ServerService.class); | ||
ContextCompat.startForegroundService(this, startIntent); | ||
bindService(startIntent, serverServiceConnection, 0); | ||
} | ||
} | ||
|
||
// Called from native code, see android_main.cpp | ||
public void executeCommand(String command) { | ||
synchronized(serverServiceMonitor) { | ||
if(serverServiceMessenger == null) { | ||
return; | ||
} | ||
try { | ||
Message message = Message.obtain(null, ServerService.MESSAGE_CODE_EXECUTE_COMMAND, 0, 0); | ||
message.getData().putString(ServerService.MESSAGE_EXTRA_COMMAND, command); | ||
serverServiceMessenger.send(message); | ||
} catch (RemoteException e) { | ||
// Connection broken | ||
unbindService(serverServiceConnection); | ||
} | ||
} | ||
} | ||
|
||
// Called from native code, see android_main.cpp | ||
public boolean isServerRunning() { | ||
synchronized(serverServiceMonitor) { | ||
return serverServiceMessenger != null; | ||
} | ||
} | ||
} |
65 changes: 0 additions & 65 deletions
65
scripts/android/files/java/org/ddnet/client/NativeMain.java
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.