|
| 1 | +package org.cuberite.android; |
| 2 | + |
| 3 | +import android.app.IntentService; |
| 4 | +import android.app.Notification; |
| 5 | +import android.app.PendingIntent; |
| 6 | +import android.content.BroadcastReceiver; |
| 7 | +import android.content.Context; |
| 8 | +import android.content.Intent; |
| 9 | +import android.content.IntentFilter; |
| 10 | +import android.graphics.BitmapFactory; |
| 11 | +import android.support.v4.content.LocalBroadcastManager; |
| 12 | +import android.support.v7.app.NotificationCompat; |
| 13 | +import android.text.Html; |
| 14 | +import android.util.Log; |
| 15 | + |
| 16 | +import java.io.File; |
| 17 | +import java.io.OutputStream; |
| 18 | +import java.util.Scanner; |
| 19 | + |
| 20 | +public class CuberiteService extends IntentService { |
| 21 | + |
| 22 | + private String log; |
| 23 | + |
| 24 | + public CuberiteService() { |
| 25 | + super("CuberiteService"); |
| 26 | + } |
| 27 | + |
| 28 | + private void addLog(String string) { |
| 29 | + String logLine = ""; |
| 30 | + String[] text = string.split("\\n"); |
| 31 | + for (String line : text) { |
| 32 | + String curText = Html.escapeHtml(line); |
| 33 | + if (curText.toLowerCase().startsWith("log: ")) { |
| 34 | + curText = curText.replaceFirst("(?i)log: ", ""); |
| 35 | + } else if (curText.toLowerCase().startsWith("info:")) { |
| 36 | + curText = curText.replaceFirst("(?i)info: ", ""); |
| 37 | + curText = "<font color= \"#FFA500\">" + curText + "</font>"; |
| 38 | + } else if (curText.toLowerCase().startsWith("warning: ")) { |
| 39 | + curText = curText.replaceFirst("(?i)warning: ", ""); |
| 40 | + curText = "<font color= \"#FF0000\">" + curText + "</font>"; |
| 41 | + } else if (curText.toLowerCase().startsWith("error: ")) { |
| 42 | + curText = curText.replaceFirst("(?i)error: ", ""); |
| 43 | + curText = "<font color=\"#8B0000\">" + curText + "</font>"; |
| 44 | + } |
| 45 | + |
| 46 | + logLine += "<br>" + curText; |
| 47 | + } |
| 48 | + log += logLine; |
| 49 | + Intent intent = new Intent("addLog"); |
| 50 | + intent.putExtra("message", logLine); |
| 51 | + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); |
| 52 | + } |
| 53 | + |
| 54 | + @Override |
| 55 | + protected void onHandleIntent(Intent intent) { |
| 56 | + Log.d(Tags.SERVICE, "Starting service..."); |
| 57 | + final String stopCommand = intent.getStringExtra("stopcommand"); |
| 58 | + final String ip = intent.getStringExtra("ip"); |
| 59 | + final String binary = intent.getStringExtra("binary"); |
| 60 | + final String location = intent.getStringExtra("location"); |
| 61 | + CharSequence text = getText(R.string.notification_cuberite_running); |
| 62 | + |
| 63 | + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0); |
| 64 | + Notification notification = new NotificationCompat.Builder(this) |
| 65 | + .setSmallIcon(R.mipmap.ic_shape) |
| 66 | + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) |
| 67 | + .setTicker(text) |
| 68 | + .setContentTitle(text) |
| 69 | + .setContentText(ip) |
| 70 | + .setContentIntent(contentIntent) |
| 71 | + .build(); |
| 72 | + startForeground(1, notification); |
| 73 | + |
| 74 | + try { |
| 75 | + // Make sure we can execute the binary |
| 76 | + new File(binary).setExecutable(true, true); |
| 77 | + // Initiate ProcessBuilder with the command at the given location |
| 78 | + ProcessBuilder processBuilder = new ProcessBuilder(binary); |
| 79 | + processBuilder.directory(new File(location).getAbsoluteFile()); |
| 80 | + processBuilder.redirectErrorStream(true); |
| 81 | + addLog("Info: Cuberite is starting..."); |
| 82 | + Log.d(Tags.SERVICE, "Starting process..."); |
| 83 | + final Process process = processBuilder.start(); |
| 84 | + |
| 85 | + // Open STDIN for the inputLine |
| 86 | + final OutputStream cuberiteSTDIN = process.getOutputStream(); |
| 87 | + |
| 88 | + // Logging thread. This thread will check cuberite's stdout (and stderr), color it and append it to the logView. This thread will wait only for next lines coming. if stdout is closed, this thread will exit |
| 89 | + new Thread(new Runnable() { |
| 90 | + @Override |
| 91 | + public void run() { |
| 92 | + Log.d(Tags.SERVICE, "Starting logging thread..."); |
| 93 | + Scanner processScanner = new Scanner(process.getInputStream()); |
| 94 | + while (processScanner.hasNextLine()) { |
| 95 | + String line = processScanner.nextLine(); |
| 96 | + Log.i(Tags.PROCESS, line); |
| 97 | + addLog(line); |
| 98 | + } |
| 99 | + processScanner.close(); |
| 100 | + } |
| 101 | + }).start(); |
| 102 | + |
| 103 | + // Communication with the activity |
| 104 | + BroadcastReceiver getLog = new BroadcastReceiver() { |
| 105 | + @Override |
| 106 | + public void onReceive(Context context, Intent intent) { |
| 107 | + Intent sendIntent = new Intent("fullLog"); |
| 108 | + sendIntent.putExtra("message", log); |
| 109 | + LocalBroadcastManager.getInstance(context).sendBroadcast(sendIntent); |
| 110 | + } |
| 111 | + }; |
| 112 | + BroadcastReceiver stop = new BroadcastReceiver() { |
| 113 | + @Override |
| 114 | + public void onReceive(Context context, Intent intent) { |
| 115 | + try { |
| 116 | + cuberiteSTDIN.write((stopCommand + "\n").getBytes()); |
| 117 | + cuberiteSTDIN.flush(); |
| 118 | + } catch (Exception e) { |
| 119 | + Log.e(Tags.SERVICE, "An error occurred when writing " + stopCommand + " to the STDIN", e); |
| 120 | + } |
| 121 | + } |
| 122 | + }; |
| 123 | + BroadcastReceiver kill = new BroadcastReceiver() { |
| 124 | + @Override |
| 125 | + public void onReceive(Context context, Intent intent) { |
| 126 | + process.destroy(); |
| 127 | + } |
| 128 | + }; |
| 129 | + BroadcastReceiver executeLine = new BroadcastReceiver() { |
| 130 | + @Override |
| 131 | + public void onReceive(Context context, Intent intent) { |
| 132 | + String line = intent.getStringExtra("message"); |
| 133 | + try { |
| 134 | + cuberiteSTDIN.write((line + "\n").getBytes()); |
| 135 | + cuberiteSTDIN.flush(); |
| 136 | + } catch (Exception e) { |
| 137 | + Log.e(Tags.SERVICE, "An error occurred when writing " + line + " to the STDIN", e);} |
| 138 | + } |
| 139 | + }; |
| 140 | + LocalBroadcastManager.getInstance(this).registerReceiver(getLog, new IntentFilter("getLog")); |
| 141 | + LocalBroadcastManager.getInstance(this).registerReceiver(stop, new IntentFilter("stop")); |
| 142 | + LocalBroadcastManager.getInstance(this).registerReceiver(kill, new IntentFilter("kill")); |
| 143 | + LocalBroadcastManager.getInstance(this).registerReceiver(executeLine, new IntentFilter("executeLine")); |
| 144 | + |
| 145 | + // Wait for the process to end. Logic waits here until cuberite has stopped. Everything after that is cleanup for the next run |
| 146 | + process.waitFor(); |
| 147 | + |
| 148 | + LocalBroadcastManager.getInstance(this).unregisterReceiver(getLog); |
| 149 | + LocalBroadcastManager.getInstance(this).unregisterReceiver(stop); |
| 150 | + LocalBroadcastManager.getInstance(this).unregisterReceiver(kill); |
| 151 | + LocalBroadcastManager.getInstance(this).unregisterReceiver(executeLine); |
| 152 | + cuberiteSTDIN.close(); |
| 153 | + LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("callback")); |
| 154 | + stopSelf(); |
| 155 | + } catch (Exception e) { |
| 156 | + Log.wtf(Tags.SERVICE, "An error occurred when starting Cuberite", e); |
| 157 | + } |
| 158 | + } |
| 159 | +} |
0 commit comments