From a9cc33fde503c6c8b0a870e0a5d4287e38a4f696 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Fri, 29 Mar 2024 17:19:01 -0700 Subject: [PATCH] Colorize the logcat. https://redmine.stoutner.com/issues/378 --- app/src/main/assets/css/theme.css | 4 +- .../main/assets/de/guide_local_storage.html | 22 +-- .../main/assets/en/guide_local_storage.html | 19 +-- .../main/assets/en/guide_tracking_ids.html | 7 +- app/src/main/assets/en/guide_user_agent.html | 9 +- .../main/assets/es/guide_local_storage.html | 23 +-- .../main/assets/fr/guide_local_storage.html | 25 +-- .../main/assets/it/guide_local_storage.html | 23 +-- .../assets/pt-rBR/guide_local_storage.html | 20 +-- .../main/assets/ru/guide_local_storage.html | 19 +-- .../main/assets/tr/guide_local_storage.html | 19 +-- .../assets/zh-rCN/guide_local_storage.html | 16 +- .../activities/GuideActivity.kt | 12 +- .../activities/LogcatActivity.kt | 161 ++++++++++++------ .../GetHeadersBackgroundTask.kt | 6 +- .../fragments/GuideWebViewFragment.kt | 10 +- .../main/res/layout/logcat_bottom_appbar.xml | 18 +- app/src/main/res/layout/logcat_top_appbar.xml | 18 +- 18 files changed, 203 insertions(+), 228 deletions(-) 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 Warning 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 Warning 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.

- + User Agent

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 Warning 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.

-

Datos de formulario

- -

Los datos de formulario contienen la información introducida en los formularios web, como los nombres de los usuarios, las direcciones, los números de teléfono, etc., - y los listan en un cuadro desplegable en futuras visitas. - A diferencia de las otras formas de almacenamiento local, los datos de los formularios no se envían al servidor web sin una interacción específica del usuario. - A partir de Android Oreo (versión 8.0, API 26), los datos de formulario de WebView fueron sustituidos por el - servicio Autofill o Autorelleno. - Por ello, los controles para los datos de los formularios ya no aparecen en los dispositivos Android más nuevos.

- -

Borrar y Salir

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/fr/guide_local_storage.html b/app/src/main/assets/fr/guide_local_storage.html index 985b6792..208cf630 100644 --- a/app/src/main/assets/fr/guide_local_storage.html +++ b/app/src/main/assets/fr/guide_local_storage.html @@ -1,9 +1,9 @@ - + + Local Storage @@ -54,7 +55,7 @@ Si l'onglet d'arrière-plan fait une demande, par exemple, pour voir s'il y a des informations mises à jour, cette demande sera envoyée sans cookies, ce qui fera que le site web vous déconnectera. Il s'agit d'une limitation qui sera supprimée avec la sortie de Privacy WebView dans la série 4.x.

-

Si les cookies sont activés mais que JavaScript est désactivé, l'icône de confidentialité sera jaune en guise d'avertissement.

+

Si les cookies sont activés mais que JavaScript est désactivé, l'icône de confidentialité sera jaune Warning en guise d'avertissement.

Cookies tiers

@@ -73,20 +74,10 @@ Il utilise plutôt JavaScript pour lire et écrire les données, ce qui signifie qu'il ne fonctionne pas lorsque JavaScript est désactivé.

-

Données de formulaire

- -

Les données de formulaire contiennent les informations saisies dans les formulaires web, comme les noms d'utilisateur, les adresses, les numéros de téléphone, - etc. et les répertorient dans une boîte déroulante lors de visites ultérieures. - Contrairement aux autres formes de stockage local, les données de formulaire ne sont pas envoyées au serveur web sans interaction spécifique de l'utilisateur. - À partir d'Android Oreo (version 8.0, API 26), les données de formulaire de WebView ont été remplacées par le - service Autofill. - Ainsi, les contrôles des données de formulaire n'apparaissent plus sur les appareils Android plus récents.

- - -

Nettoyer et Quitter<

+

Nettoyer et Quitter

La fonction Nettoyer et Quitter s'exécute chaque fois que le dernier onglet est fermé ou que Nettoyer et Quitter est sélectionnée dans le menu de navigation. Par défaut, elle efface les cookies, le stockage DOM, les données de formulaire, le logcat et le cache WebView. Ensuite, elle supprime manuellement l'ensemble des répertoires app_webview et cache. Le comportement de Nettoyer et Quitter peut être configuré dans les paramètres.

- \ 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 Warning 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.

- \ No newline at end of file + diff --git a/app/src/main/assets/pt-rBR/guide_local_storage.html b/app/src/main/assets/pt-rBR/guide_local_storage.html index 4525208e..5d318724 100644 --- a/app/src/main/assets/pt-rBR/guide_local_storage.html +++ b/app/src/main/assets/pt-rBR/guide_local_storage.html @@ -1,9 +1,9 @@ - + + Local Storage @@ -52,7 +53,7 @@ Se a guia em segundo plano fizer uma solicitação, por exemplo, para ver se há informações atualizadas, essa solicitação será enviada sem cookies, oque fará com que o site desconecte você. Esta é uma limitação que será removida com o lançamento do Privacy WebView no 4.x série.

-

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 Warning 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.

- -

Limpar e fechar

Limpar e Fechar é executado sempre que a última guia é fechada ou Limpar e Fechar é selecionado no menu de navegação. Por padrão, ele limpa os cookies, o armazenamento DOM, os dados do formulário, o logcat e o cache do WebView. Em seguida, ele exclui manualmente todos os diretórios app_webview e cache. O comportamento de Limpar e Fechar pode ser configurado nas configurações.

- \ No newline at end of file + diff --git a/app/src/main/assets/ru/guide_local_storage.html b/app/src/main/assets/ru/guide_local_storage.html index 11881203..58483326 100644 --- a/app/src/main/assets/ru/guide_local_storage.html +++ b/app/src/main/assets/ru/guide_local_storage.html @@ -1,7 +1,7 @@ - + + Local Storage @@ -50,7 +51,7 @@ Если фоновая вкладка делает запрос, например, чтобы узнать, есть ли обновленная информация, этот запрос будет отправлен без файлов cookie, что приведет к разлогиниванию. Это ограничение будет устранено с выходом Privacy WebView в версии 4.x.

-

Если cookie включены и при этом JavaScript отключен, то значок конфиденциальности будет желтого цвета в качестве предупреждения.

+

Если cookie включены и при этом JavaScript отключен, то значок конфиденциальности будет желтого цвета Warning в качестве предупреждения.

Сторонние файлы cookie

@@ -69,18 +70,10 @@ Вместо этого оно использует JavaScript для чтения и записи данных, а это означает, что оно не работает, когда JavaScript отключен.

-

Данные форм

- -

Данные форм содержат информацию, введенную в веб-формы, такую как имена пользователей, адреса, номера телефонов и т.д., и отображаются в выпадающем списке при последующих посещениях. - В отличие от других форм локального хранилища, данные форм не передаются на веб-сервер без определенного взаимодействия с пользователем. Начиная с Android Oreo (версия 8.0, API 26), - данные форм WebView были заменены сервисом автозаполнения. - Таким образом, элементы управления данными формы больше не отображаются на новых Android-устройствах.

- -

Очистить и выйти

Функция Очистить и выйти запускается каждый раз при закрытии последней вкладки или выборе Очистить и выйти из меню навигации. По умолчанию очищаются cookie, DOM-хранилище, данные формы, logcat и кэш WebView. Затем происходит ручное удаление всех каталогов app_webview и cache. Поведение опции Очистить и выйти можно настроить в настройках.

- \ 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 Warning 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系列中移除。

-

如果cookies允许,而JavaScript不允许,隐私盾牌会变成黄色来示警

+

如果cookies允许,而JavaScript不允许,隐私盾牌会变成黄色Warning来示警

第三方Cookies

@@ -58,13 +59,6 @@ 不像cookies,DOM储存不在请求头中发送数据,相反,它使用JavaScript来读写数据,意味着在禁用JavaScript时DOM不能工作。

-

表单数据

- -

表单数据包含输入到web表单中的信息,包括用户名。地址,电话等等,并且在表中罗列。不像其他本地存储的表单,没有特定的用户需求,表单不会发送到web中。 - 从Android Oreo (version 8.0, API 26)开始,WebView的表单数据被Autofill service取代。 - 因此表单数据控件不会在新的安卓设备中出现

- -

清除并退出

清除并退出会在最后一个页面退出或在导航栏选中时运行,默认清除cookies,DOM储存,表单数据,日志和WebView缓存。然后需要手动删除app_webview和cache目录。可以在设置中配置清除并退出的行为。

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 @@