From: Soren Stoutner
Date: Sat, 30 Mar 2024 00:19:01 +0000 (-0700)
Subject: Colorize the logcat. https://redmine.stoutner.com/issues/378
X-Git-Tag: v3.18~6
X-Git-Url: https://gitweb.stoutner.com/?a=commitdiff_plain;h=a9cc33fde503c6c8b0a870e0a5d4287e38a4f696;p=PrivacyBrowserAndroid.git
Colorize the logcat. https://redmine.stoutner.com/issues/378
---
diff --git a/app/src/main/assets/css/theme.css b/app/src/main/assets/css/theme.css
index aa6f4fdf..a2f28084 100644
--- a/app/src/main/assets/css/theme.css
+++ b/app/src/main/assets/css/theme.css
@@ -1,7 +1,7 @@
/*
- * Copyright 2017-2020,2022 Soren Stoutner .
+ * Copyright 2017-2020, 2022 Soren Stoutner .
*
- * This file is part of Privacy Browser Android .
+ * This file is part of Privacy Browser Android .
*
* Privacy Browser Android is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/app/src/main/assets/de/guide_local_storage.html b/app/src/main/assets/de/guide_local_storage.html
index 4161bfe8..b9f6c93f 100644
--- a/app/src/main/assets/de/guide_local_storage.html
+++ b/app/src/main/assets/de/guide_local_storage.html
@@ -1,11 +1,11 @@
-
+
+ Local Storage
@@ -56,7 +57,8 @@
wodurch sie ggf. von der Website abgemeldet werden.
Diese Einschränkung wird mit Privacy WebView in den Versionen 4.x von Privacy Browser behoben werden.
-
Wenn Cookies aktiviert sind, aber JavaScript deaktiviert ist, wird das Privatsphären-Icon zur Warnung in gelb dargestellt.
+
Wenn Cookies aktiviert sind, aber JavaScript deaktiviert ist, wird das Privatsphären-Icon zur Warnung in gelb dargestellt.
+
Drittanbieter-Cookies
@@ -64,6 +66,7 @@
Es gibt eigentlich keinen guten Grund, solche Cookies überhaupt zuzulassen. Ab Privacy Browser Version 3.8 wurde die Option daher entfernt und selbst Google plant,
Drittanbieter-Cookies in Zukunft zu deaktivieren.
+
DOM-Speicher
Der Document-Object-Model-Speicher - auch als Web-Speicher bekannt - funktioniert wie "gedopte" Cookies.
@@ -72,13 +75,6 @@
Die gespeicherten Daten werden dabei - im Gegensatz zu Cookies - nicht bei jeder Anfrage zur Gänze im Header mitgeschickt,
sondern mittels JavaScript gelesen und geschrieben, sodass diese Form der Datenspeicherung nicht funktioniert, wenn JavaScript deaktiviert ist.
-
Formulardaten
-
-
Formulardaten enthalten Informationen, die in Web-Formulare eingegeben wurden (wie z.B. Benutzernamen, Adressen, Telefonnummern, usw.) und werden bei späteren Besuchen in Auswahl-Dialogen angezeigt.
- Im Gegensatz zu in Cookies und im DOM-Speicher gespeicherten Daten werden diese Informationen nur nach Benutzer-Interaktion an den Webserver gesandt. Ab Android Oreo (Version 8.0, API 26) wurden
- WebViews Formulardaten durch Googles Autofill-Service ersetzt.
- Daher erscheinen Formulardaten auf neueren Android-Geräten nicht mehr.
-
Bereinigen und SchlieÃen
@@ -87,4 +83,4 @@
danach werden alle App-WebView- und Cache- Verzeichnisse gelöscht.
Das Verhalten von "Bereinigen und SchlieÃen" kann in den Einstellungen konfiguriert werden.
-
\ No newline at end of file
+
diff --git a/app/src/main/assets/en/guide_local_storage.html b/app/src/main/assets/en/guide_local_storage.html
index a1ccf604..55764cbe 100644
--- a/app/src/main/assets/en/guide_local_storage.html
+++ b/app/src/main/assets/en/guide_local_storage.html
@@ -1,7 +1,7 @@
-
+
+ Local Storage
@@ -49,7 +50,7 @@
If the background tab makes a request, for example, to see if there is updated information, that request will be sent without cookies, which will cause the website to log you out.
This is a limitation that will be removed with the release of Privacy WebView in the 4.x series.
-
If cookies are enabled but JavaScript is disabled, the privacy icon will be yellow as a warning.
+
If cookies are enabled but JavaScript is disabled, the privacy icon will be yellow as a warning.
Third-Party Cookies
@@ -66,18 +67,10 @@
Rather, it uses JavaScript to read and write data, which means it does not function when JavaScript is disabled.
-
Form Data
-
-
Form data contains information typed into web forms, like usernames, addresses, phone numbers, etc., and lists them in a drop-down box on future visits.
- Unlike the other forms of local storage, form data is not sent to the web server without specific user interaction. Beginning in Android Oreo (version 8.0, API 26),
- WebViewâs form data was replaced by the Autofill service.
- As such, controls for form data no longer appear on newer Android devices.
-
-
Clear and Exit
Clear and Exit runs every time the last tab is closed or Clear and Exit is selected from the navigation menu.
By default it clears the cookies, DOM storage, form data, the logcat, and the WebView cache. Then it manually deletes the entire app_webview and cache directories.
The behavior of Clear and Exit can be configured in the settings.
-
\ No newline at end of file
+
diff --git a/app/src/main/assets/en/guide_tracking_ids.html b/app/src/main/assets/en/guide_tracking_ids.html
index 9b12a1c4..d3faf088 100644
--- a/app/src/main/assets/en/guide_tracking_ids.html
+++ b/app/src/main/assets/en/guide_tracking_ids.html
@@ -1,7 +1,7 @@
-
+
+ Tracking IDs
diff --git a/app/src/main/assets/en/guide_user_agent.html b/app/src/main/assets/en/guide_user_agent.html
index 3e7e0f49..e762bb38 100644
--- a/app/src/main/assets/en/guide_user_agent.html
+++ b/app/src/main/assets/en/guide_user_agent.html
@@ -1,7 +1,7 @@
-
+
+ User Agent
@@ -41,7 +42,7 @@
The screenshot below shows a Pixel 2 XL running Android 10 with Android System WebView 84.0.4147.125 installed.
Most web servers will recognize this as a mobile browser and will display the mobile version of the site if they have one.
-
+
There is enough information in the user agent that sometimes only a few visitors to a website will be the same.
If the user agent is combined with another piece of non-unique identifying information, often it results in a unique fingerprint.
diff --git a/app/src/main/assets/es/guide_local_storage.html b/app/src/main/assets/es/guide_local_storage.html
index 23351e5d..ca9bc9ef 100644
--- a/app/src/main/assets/es/guide_local_storage.html
+++ b/app/src/main/assets/es/guide_local_storage.html
@@ -1,9 +1,9 @@
-
+
+ Local Storage
@@ -52,7 +53,7 @@
Si la pestaña en segundo plano hace una petición, por ejemplo, para ver si hay información actualizada, esa petición se enviará sin cookies, lo que hará que el sitio web cierre la sesión.
Esta es una limitación que se eliminará con el lanzamiento de Privacy WebView en la serie 4.x.
-
Si las cookies están activadas pero JavaScript está desactivado, el icono de privacidad será amarillo como advertencia.
+
Si las cookies están activadas pero JavaScript está desactivado, el icono de privacidad será amarillo como advertencia.
Cookies de terceros
@@ -70,16 +71,6 @@
Más bien, utiliza JavaScript para leer y escribir datos, lo que significa que no funciona cuando JavaScript está desactivado.
-
Borrar y salir se ejecuta cada vez que se cierra la última pestaña o se selecciona Borrar y salir en el menú de navegación.
@@ -87,4 +78,4 @@
Luego borra manualmente los directorios app_webview y cache.
El comportamiento de Borrar y Salir se puede configurar en los ajustes.
-
\ No newline at end of file
+
diff --git a/app/src/main/assets/it/guide_local_storage.html b/app/src/main/assets/it/guide_local_storage.html
index fa5cd590..efaf8f69 100644
--- a/app/src/main/assets/it/guide_local_storage.html
+++ b/app/src/main/assets/it/guide_local_storage.html
@@ -1,9 +1,9 @@
-
+
+ Local Storage
@@ -54,7 +55,7 @@
quella richiesta sarà inviata senza cookie e questo provocherà il log out dal sito.
Questa è una limitazione che sarà rimossa con il rilascio di Privacy WebView nella serie 4.x.
-
Se i cookies sono abilitati ma JavaScript è disabilitato, l'icona della privacy sarà gialla come avvertimento.
+
Se i cookies sono abilitati ma JavaScript è disabilitato, l'icona della privacy sarà gialla come avvertimento.
Cookies di terze parti
@@ -73,20 +74,10 @@
Al contrario utilizza JavaScript per leggere e scrivere i dati, il che significa che non può funzionare se JavaScript è disabilitato.
-
Dati dei moduli
-
-
I dati dei moduli contengono informazioni che sono digitate nei web forms, come il nome dell'utente, gli indirizzi, numeri di telefono, ecc.,
- e li elenca in un menù a tendina in caso di accessi futuri.
- A differenza delle altre modalità di memorizzazione locale, i dati dei moduli non vengono inviati ai web server senza che ci sia una interazione con l'utente.
- A partire da Android Oreo (versione 8.0, API 26), i dati dei moduli di WebView sono stati sostituiti dal
- servizio Autofill.
- Per questo motivo i controlli dei dati dei moduli non sono presenti nei dispositivi Android più recenti.
-
-
Elimina dati ed esci
Elimina dati ed esci viene eseguito ogni volta che viene chiusa l'ultima scheda oppure quando viene selezionato il comando Elimina dati ed esci dal menù di navigazione.
Di default questo comando cancella i cookie, il DOM storage, i dati dei moduli, il logcat e la cache di WebView.
In sostanza elimina completamente le cartelle app_webview e cache. Il comportamento di Elimina dati ed esci può essere configurato nelle impostazioni.
Se os cookies estiverem habilitados, mas o JavaScript estiver desabilitado, o Ãcone de privacidade ficará amarelo como um aviso.
+
Se os cookies estiverem habilitados, mas o JavaScript estiver desabilitado, o Ãcone de privacidade ficará amarelo como um aviso.
Cookies de terceiros
@@ -71,19 +72,10 @@
Em vez disso, ele usa JavaScript para ler e gravar dados, o que significa que não funciona quando o JavaScript está desabilitado.
-
Dados do Formulário
-
-
Os dados do formulário contêm informações digitadas em formulários da web, como nomes de usuário, endereços, números de telefone, etc., e os relaciona em uma caixa suspensa em visitas futuras.
- Ao contrário de outras formas de armazenamento local, os dados do formulário não são enviados ao servidor da web sem interação especÃfica do usuário.
- A partir do Android Oreo (versão 8.0, API 26), os dados do formulário WebView foram substituÃdos pelo
- Autofill service.
- Como tal, os controles para dados de formulário não aparecem mais em dispositivos Android mais recentes.
-
\ No newline at end of file
+
diff --git a/app/src/main/assets/tr/guide_local_storage.html b/app/src/main/assets/tr/guide_local_storage.html
index ce88b642..1a2c451a 100644
--- a/app/src/main/assets/tr/guide_local_storage.html
+++ b/app/src/main/assets/tr/guide_local_storage.html
@@ -1,7 +1,7 @@
-
+
+ Local Storage
@@ -50,7 +51,7 @@
If the background tab makes a request, for example, to see if there is updated information, that request will be sent without cookies, which will cause the website to log you out.
This is a limitation that will be removed with the release of Privacy WebView in the 4.x series.
-
If cookies are enabled but JavaScript is disabled, the privacy icon will be yellow as a warning.
+
If cookies are enabled but JavaScript is disabled, the privacy icon will be yellow as a warning.
Ãçüncü Taraf Ãerezler
@@ -67,18 +68,10 @@
Rather, it uses JavaScript to read and write data, which means it does not function when JavaScript is disabled.
-
Form Verisi
-
-
Form data contains information typed into web forms, like usernames, addresses, phone numbers, etc., and lists them in a drop-down box on future visits.
- Unlike the other forms of local storage, form data is not sent to the web server without specific user interaction. Beginning in Android Oreo (version 8.0, API 26),
- WebViewâs form data was replaced by the Autofill service.
- As such, controls for form data no longer appear on newer Android devices.
-
-
Clear and Exit
Clear and Exit runs every time the last tab is closed or Clear and Exit is selected from the navigation menu.
By default it clears the cookies, DOM storage, form data, the logcat, and the WebView cache. Then it manually deletes the entire app_webview and cache directories.
The behavior of Clear and Exit can be configured in the settings.
-
\ No newline at end of file
+
diff --git a/app/src/main/assets/zh-rCN/guide_local_storage.html b/app/src/main/assets/zh-rCN/guide_local_storage.html
index a0a608b7..373d752c 100644
--- a/app/src/main/assets/zh-rCN/guide_local_storage.html
+++ b/app/src/main/assets/zh-rCN/guide_local_storage.html
@@ -1,9 +1,9 @@
-
+
+ Local Storage
@@ -43,7 +44,7 @@
å¦æä½ å¨åå°æä¸ä¸ªé¡µé¢éè¦cookiesæ¥ç»å½ï¼èä½ å¨ä¸ä¸ªé¡µé¢éå ³éäºcookiesï¼ææ页é¢çcookiesé½ä¼è¢«å ³éãå¦æå¨åå°ç页é¢ååºè¯·æ±ï¼ä¾å¦ï¼çæ没ææ°æ¶æ¯ï¼èå¨æ²¡æcookiesçæ åµä¸éè¦ä½ éæ°ç»å½ã
è¿ä¸ªéå¶ä¼å¨éç§æµè§å¨ 4.xç³»åä¸ç§»é¤ã
-
diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/GuideActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/GuideActivity.kt
index 49f3fd60..624ba5af 100644
--- a/app/src/main/java/com/stoutner/privacybrowser/activities/GuideActivity.kt
+++ b/app/src/main/java/com/stoutner/privacybrowser/activities/GuideActivity.kt
@@ -1,7 +1,7 @@
/*
- * Copyright 2016-2023 Soren Stoutner .
+ * Copyright 2016-2024 Soren Stoutner .
*
- * This file is part of Privacy Browser Android .
+ * This file is part of Privacy Browser Android .
*
* Privacy Browser Android is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -43,19 +43,17 @@ class GuideActivity : AppCompatActivity() {
val bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
// Disable screenshots if not allowed.
- if (!allowScreenshots) {
+ if (!allowScreenshots)
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
- }
// Run the default commands.
super.onCreate(savedInstanceState)
// Set the content view.
- if (bottomAppBar) {
+ if (bottomAppBar)
setContentView(R.layout.guide_bottom_appbar)
- } else {
+ else
setContentView(R.layout.guide_top_appbar)
- }
// Get handles for the views.
val toolbar = findViewById(R.id.guide_toolbar)
diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt
index 4005443a..c12c74ec 100644
--- a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt
+++ b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt
@@ -1,7 +1,7 @@
/*
* Copyright 2019-2024 Soren Stoutner .
*
- * This file is part of Privacy Browser Android .
+ * This file is part of Privacy Browser Android .
*
* Privacy Browser Android is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,12 +24,12 @@ import android.content.ClipboardManager
import android.os.Build
import android.os.Bundle
import android.provider.OpenableColumns
+import android.util.Base64
import android.util.TypedValue
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
-import android.widget.TextView
-import android.widget.ScrollView
+import android.webkit.WebView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
@@ -50,29 +50,25 @@ import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
-import java.lang.Exception
+
import java.nio.charset.StandardCharsets
// Define the class constants.
-private const val SCROLLVIEW_POSITION = "scrollview_position"
+private const val SCROLL_Y = "A"
class LogcatActivity : AppCompatActivity() {
- // Define the class variables.
- private var scrollViewYPositionInt = 0
+ // Declare the class variables.
+ private lateinit var logcatPlainTextStringBuilder: StringBuilder
- // Define the class views.
+ // Declare the class views.
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
- private lateinit var logcatScrollView: ScrollView
- private lateinit var logcatTextView: TextView
+ private lateinit var logcatWebView: WebView
// Define the save logcat activity result launcher. It must be defined before `onCreate()` is run or the app will crash.
private val saveLogcatActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { fileUri ->
// Only save the file if the URI is not null, which happens if the user exited the file picker by pressing back.
if (fileUri != null) {
try {
- // Get the logcat string.
- val logcatString = logcatTextView.text.toString()
-
// Open an output stream.
val outputStream = contentResolver.openOutputStream(fileUri)!!
@@ -80,7 +76,7 @@ class LogcatActivity : AppCompatActivity() {
CoroutineScope(Dispatchers.Main).launch {
withContext(Dispatchers.IO) {
// Write the logcat string to the output stream.
- outputStream.write(logcatString.toByteArray(StandardCharsets.UTF_8))
+ outputStream.write(logcatPlainTextStringBuilder.toString().toByteArray(StandardCharsets.UTF_8))
// Close the output stream.
outputStream.close()
@@ -100,10 +96,10 @@ class LogcatActivity : AppCompatActivity() {
contentResolverCursor.close()
// Display a snackbar with the saved logcat information.
- Snackbar.make(logcatTextView, getString(R.string.saved, fileNameString), Snackbar.LENGTH_SHORT).show()
+ Snackbar.make(logcatWebView, getString(R.string.saved, fileNameString), Snackbar.LENGTH_SHORT).show()
} catch (exception: Exception) {
// Display a snackbar with the error message.
- Snackbar.make(logcatTextView, getString(R.string.error_saving_logcat, exception.toString()), Snackbar.LENGTH_INDEFINITE).show()
+ Snackbar.make(logcatWebView, getString(R.string.error_saving_logcat, exception.toString()), Snackbar.LENGTH_INDEFINITE).show()
}
}
}
@@ -117,25 +113,22 @@ class LogcatActivity : AppCompatActivity() {
val bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
// Disable screenshots if not allowed.
- if (!allowScreenshots) {
+ if (!allowScreenshots)
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
- }
// Run the default commands.
super.onCreate(savedInstanceState)
// Set the content view.
- if (bottomAppBar) {
+ if (bottomAppBar)
setContentView(R.layout.logcat_bottom_appbar)
- } else {
+ else
setContentView(R.layout.logcat_top_appbar)
- }
// Get handles for the views.
val toolbar = findViewById(R.id.toolbar)
swipeRefreshLayout = findViewById(R.id.swiperefreshlayout)
- logcatScrollView = findViewById(R.id.scrollview)
- logcatTextView = findViewById(R.id.logcat_textview)
+ logcatWebView = findViewById(R.id.logcat_webview)
// Set the toolbar as the action bar.
setSupportActionBar(toolbar)
@@ -148,8 +141,8 @@ class LogcatActivity : AppCompatActivity() {
// Implement swipe to refresh.
swipeRefreshLayout.setOnRefreshListener {
- // Get the current logcat.
- getLogcat()
+ // Populate the current logcat.
+ populateLogcat()
}
// Set the swipe refresh color scheme according to the theme.
@@ -167,14 +160,15 @@ class LogcatActivity : AppCompatActivity() {
// Set the swipe refresh background color.
swipeRefreshLayout.setProgressBackgroundColorSchemeColor(colorBackgroundInt)
- // Check to see if the activity has been restarted.
- if (savedInstanceState != null) {
- // Get the saved scrollview position.
- scrollViewYPositionInt = savedInstanceState.getInt(SCROLLVIEW_POSITION)
- }
+ // Restore the WebView scroll position if the activity has been restarted.
+ if (savedInstanceState != null)
+ logcatWebView.scrollY = savedInstanceState.getInt(SCROLL_Y)
+
+ // Allow loading of file:// URLs.
+ logcatWebView.settings.allowFileAccess = true
- // Get the logcat.
- getLogcat()
+ // Populate the logcat.
+ populateLogcat()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -193,14 +187,14 @@ class LogcatActivity : AppCompatActivity() {
val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
// Save the logcat in a clip data.
- val logcatClipData = ClipData.newPlainText(getString(R.string.logcat), logcatTextView.text)
+ val logcatClipData = ClipData.newPlainText(getString(R.string.logcat), logcatPlainTextStringBuilder)
// Place the clip data on the clipboard.
clipboardManager.setPrimaryClip(logcatClipData)
// Display a snackbar if the API <= 32 (Android 12L). Beginning in Android 13 the OS displays a notification that covers up the snackbar.
if (Build.VERSION.SDK_INT <= 32)
- Snackbar.make(logcatTextView, R.string.logcat_copied, Snackbar.LENGTH_SHORT).show()
+ Snackbar.make(logcatWebView, R.string.logcat_copied, Snackbar.LENGTH_SHORT).show()
// Consume the event.
true
@@ -222,11 +216,8 @@ class LogcatActivity : AppCompatActivity() {
// Wait for the process to finish.
process.waitFor()
- // Reset the scroll view Y position int.
- scrollViewYPositionInt = 0
-
// Reload the logcat.
- getLogcat()
+ populateLogcat()
} catch (exception: Exception) {
// Do nothing.
}
@@ -246,14 +237,11 @@ class LogcatActivity : AppCompatActivity() {
// Run the default commands.
super.onSaveInstanceState(savedInstanceState)
- // Get the scrollview Y position.
- val scrollViewYPositionInt = logcatScrollView.scrollY
-
- // Store the scrollview Y position in the bundle.
- savedInstanceState.putInt(SCROLLVIEW_POSITION, scrollViewYPositionInt)
+ // Store the scroll Y position in the bundle.
+ savedInstanceState.putInt(SCROLL_Y, logcatWebView.scrollY)
}
- private fun getLogcat() {
+ private fun populateLogcat() {
try {
// Get the logcat. `-b all` gets all the buffers (instead of just crash, main, and system). `-v long` produces more complete information. `-d` dumps the logcat and exits.
val getLogcatProcess = Runtime.getRuntime().exec("logcat -b all -v long -d")
@@ -261,8 +249,83 @@ class LogcatActivity : AppCompatActivity() {
// Wrap the logcat in a buffered reader.
val logcatBufferedReader = BufferedReader(InputStreamReader(getLogcatProcess.inputStream))
- // Display the logcat.
- logcatTextView.text = logcatBufferedReader.readText()
+ // Reset the logcat plain text string.
+ logcatPlainTextStringBuilder = StringBuilder()
+
+ // Create a logcat HTML string builder.
+ val logcatHtmlStringBuilder = StringBuilder()
+
+ // Populate the initial HTML.
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append("")
+
+ // Respect dark mode.
+ logcatHtmlStringBuilder.append("")
+
+ // Start the HTML body.
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append("")
+
+ // Create a logcat line string.
+ var logcatLineString: String?
+
+ while (logcatBufferedReader.readLine().also { logcatLineString = it } != null) {
+ // Populate the logcat plain text string builder.
+ logcatPlainTextStringBuilder.append(logcatLineString)
+
+ // Add a line break.
+ logcatPlainTextStringBuilder.append("\n")
+
+ // Trim the string, which is necessary for correct detection of lines that start with `at`.
+ logcatLineString = logcatLineString!!.trim()
+
+ // Apply syntax highlighting to the logcat.
+ if (logcatLineString!!.contains("crash") || logcatLineString!!.contains("Exception") ) { // Colorize crashes.
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append(logcatLineString)
+ logcatHtmlStringBuilder.append("")
+ } else if (logcatLineString!!.startsWith("at") || logcatLineString!!.startsWith("Process:") || logcatLineString!!.contains("FATAL")) { // Colorize lines relating to crashes.
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append(logcatLineString)
+ logcatHtmlStringBuilder.append("")
+ } else if (logcatLineString!!.startsWith("-")) { // Colorize the headers.
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append(logcatLineString)
+ logcatHtmlStringBuilder.append("")
+ } else if (logcatLineString!!.startsWith("[ ")) { // Colorize the time stamps.
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append(logcatLineString)
+ logcatHtmlStringBuilder.append("")
+ } else { // Display the standard lines.
+ logcatHtmlStringBuilder.append(logcatLineString)
+ }
+
+ // Add a line break.
+ logcatHtmlStringBuilder.append(" ")
+ }
+
+ // Close the HTML.
+ logcatHtmlStringBuilder.append("")
+ logcatHtmlStringBuilder.append("")
+
+ // Encode the logcat HTML.
+ val base64EncodedLogcatHtml: String = Base64.encodeToString(logcatHtmlStringBuilder.toString().toByteArray(Charsets.UTF_8), Base64.NO_PADDING)
+
+ // Load the encoded logcat.
+ logcatWebView.loadData(base64EncodedLogcatHtml, "text/html", "base64")
// Close the buffered reader.
logcatBufferedReader.close()
@@ -270,12 +333,6 @@ class LogcatActivity : AppCompatActivity() {
// Do nothing.
}
- // Update the scroll position after the text is populated.
- logcatTextView.post {
- // Set the scroll position.
- logcatScrollView.scrollY = scrollViewYPositionInt
- }
-
// Stop the swipe to refresh animation if it is displayed.
swipeRefreshLayout.isRefreshing = false
}
diff --git a/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt b/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt
index 634e4f65..cd91ecba 100644
--- a/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt
+++ b/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt
@@ -1,7 +1,7 @@
/*
- * Copyright 2017-2023 Soren Stoutner .
+ * Copyright 2017-2024 Soren Stoutner .
*
- * This file is part of Privacy Browser Android .
+ * This file is part of Privacy Browser Android .
*
* Privacy Browser Android is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -102,7 +102,7 @@ class GetHeadersBackgroundTask {
// Create a buffered string reader for the content data.
val bufferedReader = BufferedReader(InputStreamReader(contentResolver.openInputStream(contentUri)))
- // Create a buffered string reader for the content data.
+ // Create a content line string.
var contentLineString: String?
// Get the data from the buffered reader one line at a time.
diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/GuideWebViewFragment.kt b/app/src/main/java/com/stoutner/privacybrowser/fragments/GuideWebViewFragment.kt
index 5c8425cc..a8cc8448 100644
--- a/app/src/main/java/com/stoutner/privacybrowser/fragments/GuideWebViewFragment.kt
+++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/GuideWebViewFragment.kt
@@ -1,7 +1,7 @@
/*
- * Copyright 2016-2023 Soren Stoutner .
+ * Copyright 2016-2024 Soren Stoutner .
*
- * This file is part of Privacy Browser Android .
+ * This file is part of Privacy Browser Android .
*
* Privacy Browser Android is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,8 +40,8 @@ import androidx.webkit.WebViewFeature
import com.stoutner.privacybrowser.R
// Define the class constants.
-private const val TAB_NUMBER = "tab_number"
-private const val SCROLL_Y = "scroll_y"
+private const val TAB_NUMBER = "A"
+private const val SCROLL_Y = "B"
class GuideWebViewFragment : Fragment() {
// Define the class variables.
@@ -135,7 +135,7 @@ class GuideWebViewFragment : Fragment() {
9 -> tabWebView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.android_asset_path) + "/guide_interface.html")
}
- // Scroll the WebView if the saved instance state is not null.
+ // Restore the WebView scroll position if the activity has been restarted.
if (savedInstanceState != null) {
tabWebView.post {
tabWebView.scrollY = savedInstanceState.getInt(SCROLL_Y)
diff --git a/app/src/main/res/layout/logcat_bottom_appbar.xml b/app/src/main/res/layout/logcat_bottom_appbar.xml
index 69b04087..cc34fb3c 100644
--- a/app/src/main/res/layout/logcat_bottom_appbar.xml
+++ b/app/src/main/res/layout/logcat_bottom_appbar.xml
@@ -1,9 +1,9 @@
diff --git a/app/src/main/res/layout/logcat_top_appbar.xml b/app/src/main/res/layout/logcat_top_appbar.xml
index 10f487d7..1eb6a675 100644
--- a/app/src/main/res/layout/logcat_top_appbar.xml
+++ b/app/src/main/res/layout/logcat_top_appbar.xml
@@ -1,9 +1,9 @@