diff --git a/app/src/main/java/io/github/sspanak/tt9/db/exporter/AbstractExporter.java b/app/src/main/java/io/github/sspanak/tt9/db/exporter/AbstractExporter.java index a97b5734..cf5ddeff 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/exporter/AbstractExporter.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/exporter/AbstractExporter.java @@ -21,8 +21,8 @@ import java.io.OutputStream; import io.github.sspanak.tt9.util.ConsumerCompat; public abstract class AbstractExporter { - final protected static String FILE_EXTENSION = ".csv"; - final protected static String MIME_TYPE = "text/csv"; + protected static String FILE_EXTENSION = ".csv"; + protected static String MIME_TYPE = "text/csv"; protected Runnable failureHandler; protected Runnable startHandler; @@ -54,7 +54,7 @@ public abstract class AbstractExporter { if (stream == null) { throw new IOException("Failed to open output stream."); } - stream.write(getWords(activity)); + stream.write(getFileContents(activity)); } } catch (IOException e) { if (uri != null) { @@ -84,7 +84,7 @@ public abstract class AbstractExporter { } try (OutputStream stream = new FileOutputStream(file)) { - stream.write(getWords(activity)); + stream.write(getFileContents(activity)); } MediaScannerConnection.scanFile(activity, new String[]{file.getAbsolutePath()}, new String[]{MIME_TYPE}, null); @@ -163,5 +163,5 @@ public abstract class AbstractExporter { abstract protected void exportSync(Activity activity); @NonNull abstract protected String generateFileName(); - @NonNull abstract protected byte[] getWords(Activity activity) throws Exception; + @NonNull abstract protected byte[] getFileContents(Activity activity) throws Exception; } diff --git a/app/src/main/java/io/github/sspanak/tt9/db/exporter/CustomWordsExporter.java b/app/src/main/java/io/github/sspanak/tt9/db/exporter/CustomWordsExporter.java index f270309f..bf771331 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/exporter/CustomWordsExporter.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/exporter/CustomWordsExporter.java @@ -41,7 +41,7 @@ public class CustomWordsExporter extends AbstractExporter { @NonNull @Override - protected byte[] getWords(Activity activity) throws Exception { + protected byte[] getFileContents(Activity activity) throws Exception { SQLiteDatabase db = SQLiteOpener.getInstance(activity).getDb(); if (db == null) { throw new Exception("Could not open database"); diff --git a/app/src/main/java/io/github/sspanak/tt9/db/exporter/DictionaryExporter.java b/app/src/main/java/io/github/sspanak/tt9/db/exporter/DictionaryExporter.java index 2644dff0..35204a57 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/exporter/DictionaryExporter.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/exporter/DictionaryExporter.java @@ -7,12 +7,12 @@ import androidx.annotation.NonNull; import java.util.ArrayList; -import io.github.sspanak.tt9.util.Logger; import io.github.sspanak.tt9.R; -import io.github.sspanak.tt9.util.Timer; import io.github.sspanak.tt9.db.sqlite.ReadOps; import io.github.sspanak.tt9.db.sqlite.SQLiteOpener; import io.github.sspanak.tt9.languages.Language; +import io.github.sspanak.tt9.util.Logger; +import io.github.sspanak.tt9.util.Timer; public class DictionaryExporter extends AbstractExporter { private static DictionaryExporter self; @@ -62,7 +62,7 @@ public class DictionaryExporter extends AbstractExporter { @Override @NonNull - protected byte[] getWords(Activity activity) throws Exception { + protected byte[] getFileContents(Activity activity) throws Exception { SQLiteDatabase db = SQLiteOpener.getInstance(activity).getDb(); if (db == null) { throw new Exception("Could not open database"); diff --git a/app/src/main/java/io/github/sspanak/tt9/db/exporter/LogcatExporter.java b/app/src/main/java/io/github/sspanak/tt9/db/exporter/LogcatExporter.java new file mode 100644 index 00000000..c9c1d91c --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/db/exporter/LogcatExporter.java @@ -0,0 +1,85 @@ +package io.github.sspanak.tt9.db.exporter; + +import android.app.Activity; + +import androidx.annotation.NonNull; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import io.github.sspanak.tt9.util.Logger; + +public class LogcatExporter extends AbstractExporter { + private static LogcatExporter self; + private final String BASE_FILE_NAME; + private boolean includeSystemLogs; + + + public LogcatExporter() { + super(); + BASE_FILE_NAME = "tt9-logs-"; + FILE_EXTENSION = ".txt"; + MIME_TYPE = "text/plain"; + } + + + public static LogcatExporter getInstance() { + if (self == null) { + self = new LogcatExporter(); + } + return self; + } + + + public static String getLogs(boolean includeSystemLogs) { + StringBuilder log = new StringBuilder(); + try { + Process process = Runtime.getRuntime().exec("logcat -d -v threadtime io.github.sspanak.tt9:D"); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line; + while ((line = bufferedReader.readLine()) != null) { + if (includeSystemLogs || line.contains(Logger.TAG_PREFIX)) { + log.append(line).append("\n"); + } + } + } catch (IOException e) { + log.append("Error getting the logs. ").append(e.getMessage()); + } + + return log.toString(); + } + + + public LogcatExporter setIncludeSystemLogs(boolean includeSystemLogs) { + this.includeSystemLogs = includeSystemLogs; + return this; + } + + + @Override + protected void exportSync(Activity activity) { + try { + sendStart("Exporting logs..."); + write(activity); + sendSuccess(); + } catch (Exception e) { + sendFailure(); + } + } + + + @NonNull + @Override + protected String generateFileName() { + return BASE_FILE_NAME + System.currentTimeMillis() + FILE_EXTENSION; + } + + + @NonNull + @Override + protected byte[] getFileContents(Activity activity) { + return getLogs(includeSystemLogs).getBytes(); + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportAbstract.java b/app/src/main/java/io/github/sspanak/tt9/preferences/items/ItemExportAbstract.java similarity index 87% rename from app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportAbstract.java rename to app/src/main/java/io/github/sspanak/tt9/preferences/items/ItemExportAbstract.java index e6d7234f..4f8985df 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportAbstract.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/items/ItemExportAbstract.java @@ -1,19 +1,18 @@ -package io.github.sspanak.tt9.preferences.screens.languages; +package io.github.sspanak.tt9.preferences.items; import androidx.preference.Preference; import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.db.exporter.AbstractExporter; import io.github.sspanak.tt9.preferences.PreferencesActivity; -import io.github.sspanak.tt9.preferences.items.ItemClickable; import io.github.sspanak.tt9.ui.notifications.DictionaryProgressNotification; -abstract class ItemExportAbstract extends ItemClickable { +abstract public class ItemExportAbstract extends ItemClickable { final protected PreferencesActivity activity; final private Runnable onStart; final private Runnable onFinish; - ItemExportAbstract(Preference item, PreferencesActivity activity, Runnable onStart, Runnable onFinish) { + public ItemExportAbstract(Preference item, PreferencesActivity activity, Runnable onStart, Runnable onFinish) { super(item); this.activity = activity; this.onStart = onStart; @@ -75,7 +74,7 @@ abstract class ItemExportAbstract extends ItemClickable { protected void setLoadingStatus() { - onStart.run(); + if (onStart != null) onStart.run(); disable(); String loadingMessage = getExporter().getStatusMessage(); @@ -86,6 +85,6 @@ abstract class ItemExportAbstract extends ItemClickable { public void setReadyStatus() { enable(); - onFinish.run(); + if (onFinish != null) onFinish.run(); } } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/debug/DebugScreen.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/debug/DebugScreen.java index 4773d79a..ac7203a3 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/debug/DebugScreen.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/debug/DebugScreen.java @@ -2,16 +2,12 @@ package io.github.sspanak.tt9.preferences.screens.debug; import androidx.preference.SwitchPreferenceCompat; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - import io.github.sspanak.tt9.R; +import io.github.sspanak.tt9.db.exporter.LogcatExporter; import io.github.sspanak.tt9.preferences.PreferencesActivity; import io.github.sspanak.tt9.preferences.items.ItemText; import io.github.sspanak.tt9.preferences.screens.BaseScreenFragment; import io.github.sspanak.tt9.util.DeviceInfo; -import io.github.sspanak.tt9.util.Logger; public class DebugScreen extends BaseScreenFragment { public static final String NAME = "Debug"; @@ -34,6 +30,7 @@ public class DebugScreen extends BaseScreenFragment { (new ItemLogLevel(findPreference(ItemLogLevel.NAME))).populate().preview().enableClickHandler(); (new ItemInputHandlingMode(findPreference(ItemInputHandlingMode.NAME), activity.getSettings())).populate().preview().enableClickHandler(); (new ItemText(activity, findPreference(DEVICE_INFO_CONTAINER))).populate(new DeviceInfo().toString()).enableClickHandler(); + (new ItemExportLogcat(findPreference(ItemExportLogcat.NAME), activity)).enableClickHandler(); initSystemLogsSwitch(); SwitchPreferenceCompat systemLogs = findPreference(SYSTEM_LOGS_SWITCH); @@ -52,30 +49,15 @@ public class DebugScreen extends BaseScreenFragment { } private void printLogs(boolean includeSystemLogs) { - StringBuilder log = new StringBuilder(); - try { - Process process = Runtime.getRuntime().exec("logcat -d -v threadtime io.github.sspanak.tt9:D"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); - - String line; - while ((line = bufferedReader.readLine()) != null) { - if (includeSystemLogs || line.contains(Logger.TAG_PREFIX)) { - log.append(line).append("\n\n"); - } - } - } - catch (IOException e) { - log.append("Error getting the logs. ").append(e.getMessage()); - } - - if (log.toString().isEmpty()) { - log.append("No Logs"); - } - if (logsContainer == null) { logsContainer = new ItemText(activity, findPreference("debug_logs_container")); logsContainer.enableClickHandler(); } - logsContainer.populate(log.toString()); + + String logs = LogcatExporter.getLogs(includeSystemLogs).replace("\n", "\n\n"); + if (logs.isEmpty()) { + logs = "No Logs"; + } + logsContainer.populate(logs); } } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/debug/ItemExportLogcat.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/debug/ItemExportLogcat.java new file mode 100644 index 00000000..3aaa9e8a --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/debug/ItemExportLogcat.java @@ -0,0 +1,40 @@ +package io.github.sspanak.tt9.preferences.screens.debug; + +import androidx.preference.Preference; + +import io.github.sspanak.tt9.db.exporter.LogcatExporter; +import io.github.sspanak.tt9.preferences.PreferencesActivity; +import io.github.sspanak.tt9.preferences.items.ItemExportAbstract; +import io.github.sspanak.tt9.ui.notifications.DictionaryProgressNotification; + +public class ItemExportLogcat extends ItemExportAbstract { + public static final String NAME = "pref_export_logcat"; + + public ItemExportLogcat(Preference item, PreferencesActivity activity) { + super(item, activity, null, null); + } + + @Override + protected LogcatExporter getExporter() { + return LogcatExporter.getInstance(); + } + + @Override + protected boolean onStartExporting() { + return getExporter().setIncludeSystemLogs(activity.getSettings().getEnableSystemLogs()).export(activity); + } + + @Override + protected void onFinishExporting(String outputFile) { + activity.runOnUiThread(() -> { + DictionaryProgressNotification.getInstance(activity).hide(); + setReadyStatus(); + + if (outputFile == null) { + item.setSummary("Export failed"); + } else { + item.setSummary("Logs exported to: " + outputFile); + } + }); + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportCustomWords.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportCustomWords.java index e1b44b7e..213d270f 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportCustomWords.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportCustomWords.java @@ -5,6 +5,7 @@ import androidx.preference.Preference; import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.db.exporter.CustomWordsExporter; import io.github.sspanak.tt9.preferences.PreferencesActivity; +import io.github.sspanak.tt9.preferences.items.ItemExportAbstract; class ItemExportCustomWords extends ItemExportAbstract { final public static String NAME = "dictionary_export_custom"; diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportDictionary.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportDictionary.java index cfbccd63..5dd98486 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportDictionary.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemExportDictionary.java @@ -2,10 +2,11 @@ package io.github.sspanak.tt9.preferences.screens.languages; import androidx.preference.Preference; -import io.github.sspanak.tt9.util.Logger; import io.github.sspanak.tt9.db.exporter.DictionaryExporter; import io.github.sspanak.tt9.languages.LanguageCollection; import io.github.sspanak.tt9.preferences.PreferencesActivity; +import io.github.sspanak.tt9.preferences.items.ItemExportAbstract; +import io.github.sspanak.tt9.util.Logger; class ItemExportDictionary extends ItemExportAbstract { final public static String NAME = "dictionary_export"; diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHacks.java b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHacks.java index baccec0d..b13c8a4d 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHacks.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHacks.java @@ -14,6 +14,10 @@ class SettingsHacks extends BaseSettings { return getStringifiedInt("pref_log_level", Logger.LEVEL); } + public boolean getEnableSystemLogs() { + return prefs.getBoolean("pref_enable_system_logs", false); + } + public int getInputHandlingMode() { return getStringifiedInt("pref_input_handling_mode", ItemInputHandlingMode.NORMAL); } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/notifications/DictionaryProgressNotification.java b/app/src/main/java/io/github/sspanak/tt9/ui/notifications/DictionaryProgressNotification.java index 9e550046..e2ffc2e8 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/notifications/DictionaryProgressNotification.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/notifications/DictionaryProgressNotification.java @@ -68,7 +68,7 @@ public class DictionaryProgressNotification extends DictionaryNotification { @Override - protected void hide() { + public void hide() { progress = maxProgress = 0; super.hide(); } diff --git a/app/src/main/res/xml/prefs_screen_debug.xml b/app/src/main/res/xml/prefs_screen_debug.xml index 1578d6a0..6bb38f27 100644 --- a/app/src/main/res/xml/prefs_screen_debug.xml +++ b/app/src/main/res/xml/prefs_screen_debug.xml @@ -30,6 +30,11 @@ app:layout="@layout/pref_switch" app:title="System Logs" /> + +