diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7154b5f..0a0aa4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -161,6 +161,11 @@ android:exported="false" /> + + logcatReader.addMarker()); + findViewById(R.id.log_marker_button).setOnClickListener(v -> getLogcatReader().ifPresent(LogcatReader::addMarker)); - findViewById(R.id.toggle_recording_button).setOnClickListener(v -> { + findViewById(R.id.toggle_recording_button).setOnClickListener(v -> getLogcatReader().ifPresent(logcatReader -> { if (logcatReader.isRecording()) { Throwable error = logcatReader.stopRecording(); - if (error == null) { - Toast.makeText(this, "recording stopped", Toast.LENGTH_SHORT).show(); - return; - } - Log.e(TAG, "error during recording", error); - new AlertDialog.Builder(this) - .setTitle("Log recording error") - .setMessage("an error happened during the recording:\n\n" + error.getClass().getSimpleName() + ": " + error.getMessage()) - .setPositiveButton("close", null) - .show(); + if (error != null) onRecordingError(error); return; } @@ -97,16 +92,15 @@ public class DebugActivity extends AppCompatActivity { File logFile = getFilesDir().toPath().resolve(name).toFile(); try { logcatReader.startRecording(logFile); - Toast.makeText(this, "recording started", Toast.LENGTH_SHORT).show(); } catch (IOException e) { Log.e(TAG, "failed to start recording", e); + onRecordingError(e); } }) .setNegativeButton("cancel", null) .setCancelable(false) .show(); - - }); + })); if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -116,8 +110,6 @@ public class DebugActivity extends AppCompatActivity { autoScrollSwitch.setOnCheckedChangeListener((v, checked) -> autoScroll = checked); RecyclerView logRecyclerView = findViewById(R.id.log_recycler); - LogUiAdapter logUiAdapter = new LogUiAdapter(); - logRecyclerView.setLayoutManager(new LinearLayoutManager(this)); logRecyclerView.setAdapter(logUiAdapter); logRecyclerView.setItemAnimator(null); // does not work with fast-paced logs @@ -130,8 +122,10 @@ public class DebugActivity extends AppCompatActivity { } }); - logcatReader = new LogcatReader(logUiAdapter); - logcatReader.start(); + logUiAdapter.onLog(null, "connecting to log service..."); + + connector = new GeargrinderServiceConnector(TAG, this, this); + connector.bindLogService(BIND_AUTO_CREATE | BIND_IMPORTANT); if (AUTOSTART_TCP_SERVER) startService(new Intent(this, ConnectionService.class) @@ -141,7 +135,56 @@ public class DebugActivity extends AppCompatActivity { @Override protected void onDestroy() { super.onDestroy(); - logcatReader.destroy(); + getLogcatReader().ifPresent(logcatReader -> logcatReader.unregisterUiListener(logUiAdapter)); + connector.destroy(); + } + + private Optional getLogcatReader() { + return connector.getLogBinder() + .map(LogService.ServiceBinder::getLogcatReader); + } + + public void updateRecordingStatus(boolean recording) { + Button toggleRecordingButton = findViewById(R.id.toggle_recording_button); + toggleRecordingButton.setText(recording ? "stop recording" : "start recording"); + } + + @Override + public void onLogServiceConnected(LogService.ServiceBinder binder) { + binder.getLogcatReader().registerUiListener(logUiAdapter); + binder.getLogcatReader().registerUiListener(this); + findViewById(R.id.log_marker_button).setEnabled(true); + findViewById(R.id.toggle_recording_button).setEnabled(true); + updateRecordingStatus(binder.getLogcatReader().isRecording()); + } + + @Override + public void onRecordingStart(File file) { + runOnUiThread(() -> { + updateRecordingStatus(true); + Toast.makeText(this, "recording started", Toast.LENGTH_SHORT).show(); + }); + } + + @Override + public void onRecordingError(Throwable t) { + runOnUiThread(() -> { + Log.e(TAG, "error during recording", t); + new AlertDialog.Builder(this) + .setTitle("Log recording error") + .setMessage("an error happened during the recording:\n\n" + t.getClass().getSimpleName() + ": " + t.getMessage()) + .setPositiveButton("close", null) + .setCancelable(false) + .show(); + }); + } + + @Override + public void onRecordingStop() { + runOnUiThread(() -> { + updateRecordingStatus(false); + Toast.makeText(this, "recording stopped", Toast.LENGTH_SHORT).show(); + }); } @Override diff --git a/app/src/main/java/io/benwiegand/projection/geargrinder/LogService.java b/app/src/main/java/io/benwiegand/projection/geargrinder/LogService.java new file mode 100644 index 0000000..57604bb --- /dev/null +++ b/app/src/main/java/io/benwiegand/projection/geargrinder/LogService.java @@ -0,0 +1,57 @@ +package io.benwiegand.projection.geargrinder; + +import android.app.Service; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +import java.io.File; + +import io.benwiegand.projection.geargrinder.logs.LogcatReader; + +public class LogService extends Service implements LogcatReader.UiLogListener { + + private final LogcatReader logcatReader = new LogcatReader(); + private final ServiceBinder binder = new ServiceBinder(); + + @Override + public void onCreate() { + super.onCreate(); + logcatReader.registerUiListener(this); + logcatReader.start(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + logcatReader.unregisterUiListener(this); + logcatReader.destroy(); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + @Override + public void onRecordingStart(File file) { + startService(new Intent(this, LogService.class)); + } + + @Override + public void onRecordingStop() { + stopService(new Intent(this, LogService.class)); + } + + public class ServiceBinder extends Binder { + + public LogcatReader getLogcatReader() { + return logcatReader; + } + + } + +} diff --git a/app/src/main/java/io/benwiegand/projection/geargrinder/logs/LogcatReader.java b/app/src/main/java/io/benwiegand/projection/geargrinder/logs/LogcatReader.java index 6e34de7..71b9a50 100644 --- a/app/src/main/java/io/benwiegand/projection/geargrinder/logs/LogcatReader.java +++ b/app/src/main/java/io/benwiegand/projection/geargrinder/logs/LogcatReader.java @@ -8,6 +8,10 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Writer; import java.nio.charset.StandardCharsets; +import java.util.ArrayDeque; +import java.util.LinkedList; +import java.util.Queue; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,19 +23,18 @@ public class LogcatReader { private static final Pattern LOGCAT_REGEX = Pattern.compile("^(?[0-9]+-[0-9]+) +(?