1
0
Fork 0

created a debugging screen for viewing the application logs

This commit is contained in:
sspanak 2023-08-02 17:04:13 +03:00
parent 9f65cb5ce8
commit 8b57289746
19 changed files with 190 additions and 40 deletions

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/pref_padding_horizontal"
android:paddingVertical="@dimen/pref_padding_vertical">
<TextView
android:id="@android:id/summary"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.TextView" />
</LinearLayout>

View file

@ -21,12 +21,13 @@
<string name="pref_category_about">About</string>
<string name="pref_category_abc_mode">ABC Mode</string>
<string name="pref_category_appearance">Appearance</string>
<string name="pref_category_debug_options" translatable="false">Debug Options</string>
<string name="pref_category_log_messages" translatable="false">Recent Log Messages</string>
<string name="pref_category_predictive_mode">Predictive Mode</string>
<string name="pref_category_function_keys">Select Hotkeys</string>
<string name="pref_category_keypad">Keypad</string>
<string name="pref_category_setup">Initial Setup</string>
<string name="pref_abc_auto_accept">Automatic Letter Select</string>
<string name="pref_abc_auto_accept_summary">Automatically type the selected letter after a short delay.</string>
<string name="pref_auto_space">Automatic Space</string>
@ -38,6 +39,8 @@
<string name="pref_dark_theme_yes">Yes</string>
<string name="pref_dark_theme_no">No</string>
<string name="pref_dark_theme_auto">Auto</string>
<string name="pref_debug_logs" translatable="false">Detailed Debug Logs</string>
<string name="pref_system_logs" translatable="false">System Logs</string>
<string name="pref_double_zero_char">Character for Double 0-key Press</string>
<string name="pref_show_soft_function_keys">Show On-Screen Keys</string>
<string name="pref_show_soft_numpad">Show On-Screen Numpad</string>

View file

@ -44,6 +44,7 @@
app:singleLineTitle="true">
<Preference
app:fragment="io.github.sspanak.tt9.preferences.DebugScreen"
app:key="version_info"
app:layout="@layout/pref_text"
app:title="@string/app_name" />

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto" app:orderingFromXml="true">
<SwitchPreferenceCompat
app:key="pref_enable_debug_logs"
app:layout="@layout/pref_switch"
app:title="@string/pref_debug_logs" />
<SwitchPreferenceCompat
app:key="pref_enable_system_logs"
app:layout="@layout/pref_switch"
app:title="@string/pref_system_logs" />
<PreferenceCategory
app:title="@string/pref_category_log_messages"
app:layout="@layout/pref_category"
app:singleLineTitle="true">
<Preference
app:key="debug_logs_container"
app:summary="--"
app:layout="@layout/pref_plain_text">
</Preference>
</PreferenceCategory>
</PreferenceScreen>

View file

@ -3,39 +3,48 @@ package io.github.sspanak.tt9;
import android.util.Log;
public class Logger {
public static final int LEVEL = BuildConfig.DEBUG ? Log.DEBUG : Log.ERROR;
public static final String TAG_PREFIX = "tt9/";
public static int LEVEL = BuildConfig.DEBUG ? Log.DEBUG : Log.ERROR;
static public boolean isDebugLevel() {
public static boolean isDebugLevel() {
return LEVEL == Log.DEBUG;
}
public static void setDebugLevel() {
LEVEL = Log.DEBUG;
}
public static void setDefaultLevel() {
LEVEL = Log.ERROR;
}
static public void v(String tag, String msg) {
if (LEVEL <= Log.VERBOSE) {
Log.v(tag, msg);
Log.v(TAG_PREFIX + tag, msg);
}
}
static public void d(String tag, String msg) {
if (LEVEL <= Log.DEBUG) {
Log.d(tag, msg);
Log.d(TAG_PREFIX + tag, msg);
}
}
static public void i(String tag, String msg) {
if (LEVEL <= Log.INFO) {
Log.i(tag, msg);
Log.i(TAG_PREFIX + tag, msg);
}
}
static public void w(String tag, String msg) {
if (LEVEL <= Log.WARN) {
Log.w(tag, msg);
Log.w(TAG_PREFIX + tag, msg);
}
}
static public void e(String tag, String msg) {
if (LEVEL <= Log.ERROR) {
Log.e(tag, msg);
Log.e(TAG_PREFIX + tag, msg);
}
}
}

View file

@ -146,11 +146,11 @@ public class DictionaryDb {
} catch (SQLiteConstraintException e) {
String msg = "Constraint violation when inserting a word: '" + dbWord.word + "' / sequence: '" + dbWord.sequence + "', for language: " + dbWord.langId
+ ". " + e.getMessage();
Logger.e("tt9/insertWord", msg);
Logger.e("insertWord", msg);
statusHandler.accept(1);
} catch (Exception e) {
String msg = "Failed inserting word: '" + dbWord.word + "' / sequence: '" + dbWord.sequence + "', for language: " + dbWord.langId + ". " + e.getMessage();
Logger.e("tt9/insertWord", msg);
Logger.e("insertWord", msg);
statusHandler.accept(2);
}
}).start();
@ -270,13 +270,13 @@ public class DictionaryDb {
ArrayList<String> wordList = new ArrayList<>(maxWords);
if (sequence == null || sequence.length() == 0) {
Logger.w("tt9/db.getWords", "Attempting to get words for an empty sequence.");
Logger.w("db.getWords", "Attempting to get words for an empty sequence.");
sendWords(dataHandler, wordList);
return;
}
if (language == null) {
Logger.w("tt9/db.getWords", "Attempting to get words for NULL language.");
Logger.w("db.getWords", "Attempting to get words for NULL language.");
sendWords(dataHandler, wordList);
return;
}

View file

@ -294,7 +294,7 @@ public class DictionaryLoader {
private void sendFileCount(int fileCount) {
if (onStatusChange == null) {
Logger.w(
"tt9/DictionaryLoader.sendFileCount",
"DictionaryLoader.sendFileCount",
"Cannot send file count without a status Handler. Ignoring message.");
return;
}
@ -308,7 +308,7 @@ public class DictionaryLoader {
private void sendProgressMessage(Language language, int progress, int progressUpdateInterval) {
if (onStatusChange == null) {
Logger.w(
"tt9/DictionaryLoader.sendProgressMessage",
"DictionaryLoader.sendProgressMessage",
"Cannot send progress without a status Handler. Ignoring message.");
return;
}
@ -331,7 +331,7 @@ public class DictionaryLoader {
private void sendError(String message, int langId) {
if (onStatusChange == null) {
Logger.w("tt9/DictionaryLoader.sendError", "Cannot send an error without a status Handler. Ignoring message.");
Logger.w("DictionaryLoader.sendError", "Cannot send an error without a status Handler. Ignoring message.");
return;
}
@ -344,7 +344,7 @@ public class DictionaryLoader {
private void sendImportError(String message, int langId, long fileLine, String word) {
if (onStatusChange == null) {
Logger.w("tt9/DictionaryLoader.sendError", "Cannot send an import error without a status Handler. Ignoring message.");
Logger.w("DictionaryLoader.sendError", "Cannot send an import error without a status Handler. Ignoring message.");
return;
}

View file

@ -751,7 +751,7 @@ public class TraditionalT9 extends KeyPadHandler {
textField.setText(word);
mInputMode.reset();
} catch (Exception e) {
Logger.w("tt9/restoreLastWord", "Could not restore the last added word. " + e.getMessage());
Logger.w("restoreLastWord", "Could not restore the last added word. " + e.getMessage());
}
}

View file

@ -18,7 +18,7 @@ public class InputModeValidator {
}
if (validLanguageIds.size() == 0) {
validLanguageIds.add(LanguageCollection.getDefault(context).getId());
Logger.e("tt9/validateEnabledLanguages", "The language list seems to be corrupted. Resetting to first language only.");
Logger.e("validateEnabledLanguages", "The language list seems to be corrupted. Resetting to first language only.");
}
return validLanguageIds;
@ -34,7 +34,7 @@ public class InputModeValidator {
Language validLanguage = LanguageCollection.getLanguage(context, validLanguageIds.get(0));
validLanguage = validLanguage != null ? validLanguage : LanguageCollection.getDefault(context);
Logger.w("tt9/validateLanguage", error + " Enforcing language: " + validLanguage.getId());
Logger.w("validateLanguage", error + " Enforcing language: " + validLanguage.getId());
return validLanguage;
}
@ -51,7 +51,7 @@ public class InputModeValidator {
}
if (newModeId != oldModeId) {
Logger.w("tt9/validateMode", "Invalid input mode: " + oldModeId + " Enforcing: " + newModeId);
Logger.w("validateMode", "Invalid input mode: " + oldModeId + " Enforcing: " + newModeId);
}
return newModeId;
@ -60,7 +60,7 @@ public class InputModeValidator {
public static void validateTextCase(InputMode inputMode, int newTextCase) {
if (!inputMode.setTextCase(newTextCase)) {
inputMode.defaultTextCase();
Logger.w("tt9/validateTextCase", "Invalid text case: " + newTextCase + " Enforcing: " + inputMode.getTextCase());
Logger.w("validateTextCase", "Invalid text case: " + newTextCase + " Enforcing: " + inputMode.getTextCase());
}
}
}

View file

@ -43,7 +43,7 @@ abstract public class InputMode {
case MODE_PASSTHROUGH:
return new ModePassthrough();
default:
Logger.w("tt9/InputMode", "Defaulting to mode: " + Mode123.class.getName() + " for unknown InputMode: " + mode);
Logger.w("InputMode", "Defaulting to mode: " + Mode123.class.getName() + " for unknown InputMode: " + mode);
case MODE_123:
return new Mode123();
}

View file

@ -147,7 +147,7 @@ public class ModePredictive extends InputMode {
}
stem = "";
Logger.d("tt9/setWordStem", "Stem filter cleared");
Logger.d("setWordStem", "Stem filter cleared");
return true;
}
@ -182,13 +182,13 @@ public class ModePredictive extends InputMode {
stem = sanitizedStem.toLowerCase(language.getLocale());
isStemFuzzy = !exact;
Logger.d("tt9/setWordStem", "Stem is now: " + stem + (isStemFuzzy ? " (fuzzy)" : ""));
Logger.d("setWordStem", "Stem is now: " + stem + (isStemFuzzy ? " (fuzzy)" : ""));
return true;
} catch (Exception e) {
isStemFuzzy = false;
stem = "";
Logger.w("tt9/setWordStem", "Ignoring invalid stem: " + newStem + ". " + e.getMessage());
Logger.w("setWordStem", "Ignoring invalid stem: " + newStem + ". " + e.getMessage());
return false;
}
}
@ -284,7 +284,7 @@ public class ModePredictive extends InputMode {
DictionaryDb.incrementWordFrequency(language, currentWord, sequence);
}
} catch (Exception e) {
Logger.e("tt9/ModePredictive", "Failed incrementing priority of word: '" + currentWord + "'. " + e.getMessage());
Logger.e("ModePredictive", "Failed incrementing priority of word: '" + currentWord + "'. " + e.getMessage());
}
}

View file

@ -20,6 +20,7 @@ import io.github.sspanak.tt9.ime.helpers.GlobalKeyboardSettings;
import io.github.sspanak.tt9.ime.helpers.InputModeValidator;
import io.github.sspanak.tt9.preferences.helpers.Hotkeys;
import io.github.sspanak.tt9.preferences.screens.AppearanceScreen;
import io.github.sspanak.tt9.preferences.screens.DebugScreen;
import io.github.sspanak.tt9.preferences.screens.DictionariesScreen;
import io.github.sspanak.tt9.preferences.screens.HotkeysScreen;
import io.github.sspanak.tt9.preferences.screens.KeyPadScreen;
@ -84,6 +85,8 @@ public class PreferencesActivity extends AppCompatActivity implements Preference
switch (name) {
case "Appearance":
return new AppearanceScreen(this);
case "Debug":
return new DebugScreen(this);
case "Dictionaries":
return new DictionariesScreen(this);
case "Hotkeys":

View file

@ -91,7 +91,7 @@ public class SettingsStore {
Set<String> validLanguageIds = new HashSet<>();
for (String langId : languageIds) {
if (!validateSavedLanguage(Integer.parseInt(langId), "tt9/saveEnabledLanguageIds")){
if (!validateSavedLanguage(Integer.parseInt(langId), "saveEnabledLanguageIds")){
continue;
}
@ -99,7 +99,7 @@ public class SettingsStore {
}
if (validLanguageIds.size() == 0) {
Logger.w("tt9/saveEnabledLanguageIds", "Refusing to save an empty language list");
Logger.w("saveEnabledLanguageIds", "Refusing to save an empty language list");
return;
}
@ -116,7 +116,7 @@ public class SettingsStore {
boolean isTextCaseValid = isIntInList(
textCase,
new ArrayList<>(Arrays.asList(InputMode.CASE_CAPITALIZE, InputMode.CASE_LOWER, InputMode.CASE_UPPER)),
"tt9/saveTextCase",
"saveTextCase",
"Not saving invalid text case: " + textCase
);
@ -132,7 +132,7 @@ public class SettingsStore {
}
public void saveInputLanguage(int language) {
if (validateSavedLanguage(language, "tt9/saveInputLanguage")){
if (validateSavedLanguage(language, "saveInputLanguage")){
prefsEditor.putInt("pref_input_language", language);
prefsEditor.apply();
}
@ -147,7 +147,7 @@ public class SettingsStore {
boolean isModeValid = isIntInList(
mode,
new ArrayList<>(Arrays.asList(InputMode.MODE_123, InputMode.MODE_PREDICTIVE, InputMode.MODE_ABC)),
"tt9/saveInputMode",
"saveInputMode",
"Not saving invalid input mode: " + mode
);

View file

@ -18,7 +18,7 @@ public class ItemDropDown {
protected void populate(LinkedHashMap<Integer, String> values) {
if (item == null) {
Logger.w("tt9/ItemDropDown.populate", "Cannot populate a NULL item. Ignoring.");
Logger.w("ItemDropDown.populate", "Cannot populate a NULL item. Ignoring.");
return;
}
@ -35,7 +35,7 @@ public class ItemDropDown {
public ItemDropDown enableClickHandler() {
if (item == null) {
Logger.w("tt9/SectionKeymap.populateItem", "Cannot set a click listener a NULL item. Ignoring.");
Logger.w("SectionKeymap.populateItem", "Cannot set a click listener a NULL item. Ignoring.");
return this;
}

View file

@ -30,7 +30,7 @@ public class ItemSelectZeroKeyCharacter {
public ItemSelectZeroKeyCharacter populate() {
if (item == null) {
Logger.w("tt9/ItemSelectZeroKeyChar.populate", "Cannot populate a NULL item. Ignoring.");
Logger.w("ItemSelectZeroKeyChar.populate", "Cannot populate a NULL item. Ignoring.");
return this;
}
@ -44,7 +44,7 @@ public class ItemSelectZeroKeyCharacter {
public void activate() {
if (item == null) {
Logger.w("tt9/ItemSelectZeroKeyChar.activate", "Cannot set a click listener a NULL item. Ignoring.");
Logger.w("ItemSelectZeroKeyChar.activate", "Cannot set a click listener a NULL item. Ignoring.");
return;
}

View file

@ -70,7 +70,7 @@ public class SectionKeymap {
private void populateItem(DropDownPreference dropDown) {
if (dropDown == null) {
Logger.w("tt9/SectionKeymap.populateItem", "Cannot populate a NULL item. Ignoring.");
Logger.w("SectionKeymap.populateItem", "Cannot populate a NULL item. Ignoring.");
return;
}
@ -98,7 +98,7 @@ public class SectionKeymap {
private void onItemClick(DropDownPreference item) {
if (item == null) {
Logger.w("tt9/SectionKeymap.populateItem", "Cannot set a click listener a NULL item. Ignoring.");
Logger.w("SectionKeymap.populateItem", "Cannot set a click listener a NULL item. Ignoring.");
return;
}
@ -140,7 +140,7 @@ public class SectionKeymap {
for (DropDownPreference item : items) {
if (item != null && !dropDown.getKey().equals(item.getKey()) && key.equals(item.getValue())) {
Logger.i("tt9/SectionKeymap.validateKey", "Key: '" + key + "' is already in use for function: " + item.getKey());
Logger.i("SectionKeymap.validateKey", "Key: '" + key + "' is already in use for function: " + item.getKey());
return false;
}
}

View file

@ -41,7 +41,7 @@ abstract class BaseScreenFragment extends PreferenceFragmentCompat {
if (activity == null) {
Logger.w(
"tt9/MainSettingsScreen",
"MainSettingsScreen",
"Starting up without an Activity. Preference Items will not be fully initialized."
);
return;

View file

@ -0,0 +1,95 @@
package io.github.sspanak.tt9.preferences.screens;
import androidx.preference.Preference;
import androidx.preference.SwitchPreferenceCompat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
public class DebugScreen extends BaseScreenFragment {
private static final String DEBUG_LOGS_SWITCH = "pref_enable_debug_logs";
private static final String SYSTEM_LOGS_SWITCH = "pref_enable_system_logs";
private static final String LOGS_CONTAINER = "debug_logs_container";
public DebugScreen() { init(); }
public DebugScreen(PreferencesActivity activity) { init(activity); }
@Override protected int getTitle() { return R.string.pref_category_debug_options; }
@Override protected int getXml() { return R.xml.prefs_screen_debug; }
@Override
protected void onCreate() {
initLogMessagesSwitch();
initSystemLogsSwitch();
SwitchPreferenceCompat systemLogs = findPreference(SYSTEM_LOGS_SWITCH);
boolean includeSystemLogs = systemLogs != null && systemLogs.isChecked();
printLogs(includeSystemLogs);
}
private void initLogMessagesSwitch() {
SwitchPreferenceCompat msgSwitch = findPreference(DEBUG_LOGS_SWITCH);
if (msgSwitch == null) {
Logger.w("DebugScreen", "Debug logs switch not found.");
return;
}
msgSwitch.setChecked(Logger.isDebugLevel());
msgSwitch.setOnPreferenceChangeListener((Preference p, Object newValue) -> {
if ((boolean) newValue) {
Logger.setDebugLevel();
} else {
Logger.setDefaultLevel();
}
return true;
});
}
private void initSystemLogsSwitch() {
SwitchPreferenceCompat systemLogs = findPreference(SYSTEM_LOGS_SWITCH);
if (systemLogs == null) {
Logger.w("DebugScreen", "System logs switch not found.");
return;
}
systemLogs.setOnPreferenceChangeListener((p, newValue) -> {
printLogs((boolean) newValue);
return true;
});
}
private void printLogs(boolean includeSystemLogs) {
Preference logsContainer = findPreference(LOGS_CONTAINER);
if (logsContainer == null) {
Logger.w("DebugScreen", "Logs container not found. Cannot print logs");
return;
}
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");
}
logsContainer.setSummary(log.toString());
}
}

View file

@ -59,7 +59,7 @@ public class MainSettingsScreen extends BaseScreenFragment {
intent.setData(Uri.parse(versionedHelpUrl));
helpSection.setIntent(intent);
} catch (Exception e) {
Logger.w("tt9/MainSettingsScreen", "Could not set versioned help URL. Falling back to the default. " + e.getMessage());
Logger.w("MainSettingsScreen", "Could not set versioned help URL. Falling back to the default. " + e.getMessage());
}
}