RunBin/app/src/main/java/de/mrbesen/runbin/RunService.java

210 lines
8.5 KiB
Java

package de.mrbesen.runbin;
import android.app.IntentService;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.text.Html;
import android.util.Log;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class RunService extends IntentService {
private String log;
private static final String tag = "Service";
public RunService() {
super("RunService");
}
private void addLog(String string) {
String logLine = "";
String[] text = string.split("\\n");
for (String line : text) {
String curText = Html.escapeHtml(line);
if (curText.toLowerCase().startsWith("log: ")) {
curText = curText.replaceFirst("(?i)log: ", "");
} else if (curText.toLowerCase().startsWith("info:")) {
curText = curText.replaceFirst("(?i)info: ", "");
curText = "<font color= \"#FFA500\">" + curText + "</font>";
} else if (curText.toLowerCase().startsWith("warning: ")) {
curText = curText.replaceFirst("(?i)warning: ", "");
curText = "<font color= \"#FF0000\">" + curText + "</font>";
} else if (curText.toLowerCase().startsWith("error: ")) {
curText = curText.replaceFirst("(?i)error: ", "");
curText = "<font color=\"#8B0000\">" + curText + "</font>";
}
logLine += "<br>" + curText;
}
log += logLine;
Intent intent = new Intent("addLog");
intent.putExtra("message", logLine);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(tag, "Starting service...");
final String binarydl = intent.getStringExtra("binary");
final File execpath = new File(intent.getStringExtra("path"));
final String param = intent.getStringExtra("param");
final File binpath = getFilesDir();
execpath.mkdirs();
binpath.mkdirs();
final String binname = FilenameUtils.getName(binarydl);
CharSequence text = "Running...";
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setTicker(text)
.setContentTitle(text)
.setContentText(execpath + " " + binarydl)
.setContentIntent(contentIntent)
.build();
startForeground(1, notification);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
wakeLock.acquire();
try {
// Make sure we can execute the binary
//install binary
Log.d(tag, "Download " + binarydl + " into " + binpath + " called " + binname );
File bin = new File(binpath, binname);
download(binarydl, bin);
bin.setExecutable(true);
// Initiate ProcessBuilder with the command at the given location
ProcessBuilder processBuilder = new ProcessBuilder(bin.getAbsolutePath(), param);
processBuilder.directory(execpath.getAbsoluteFile());
processBuilder.redirectErrorStream(true);
addLog("Info: Process is starting...");
Log.d(tag, "Starting process. Folder: " + execpath + " with params: " + param);
final Process process = processBuilder.start();
// Open STDIN for the inputLine
final OutputStream cuberiteSTDIN = process.getOutputStream();
// Logging thread. This thread will check 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
new Thread(new Runnable() {
@Override
public void run() {
Log.d(tag, "Starting logging thread...");
Scanner processScanner = new Scanner(process.getInputStream());
while (processScanner.hasNextLine()) {
String line = processScanner.nextLine();
Log.i("Process", line);
addLog(line);
}
processScanner.close();
}
}).start();
// Communication with the activity
BroadcastReceiver getLog = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Intent sendIntent = new Intent("fullLog");
sendIntent.putExtra("message", log);
LocalBroadcastManager.getInstance(context).sendBroadcast(sendIntent);
}
};
BroadcastReceiver kill = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
process.destroy();
}
};
BroadcastReceiver executeLine = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String line = intent.getStringExtra("message");
try {
cuberiteSTDIN.write((line + "\n").getBytes());
cuberiteSTDIN.flush();
} catch (Exception e) {
Log.e(tag, "An error occurred when writing " + line + " to the STDIN", e);}
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(getLog, new IntentFilter("getLog"));
LocalBroadcastManager.getInstance(this).registerReceiver(kill, new IntentFilter("kill"));
LocalBroadcastManager.getInstance(this).registerReceiver(executeLine, new IntentFilter("executeLine"));
// Wait for the process to end. Logic waits here until process has stopped. Everything after that is cleanup for the next run
process.waitFor();
Log.d(tag, "Stopped Process.");
LocalBroadcastManager.getInstance(this).unregisterReceiver(getLog);
LocalBroadcastManager.getInstance(this).unregisterReceiver(kill);
LocalBroadcastManager.getInstance(this).unregisterReceiver(executeLine);
cuberiteSTDIN.close();
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("callback"));
stopSelf();
} catch (Exception e) {
Log.wtf(tag, "An error occurred when starting process", e);
addLog("error: Failed.");
} finally {
wakeLock.release();
}
}
private void download(String surl, final File file) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(surl);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
return;
// download the file
input = connection.getInputStream();
output = new FileOutputStream(file);
byte data[] = new byte[4096];
int count;
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
}
}