Convert the views and data classes to Kotlin. https://redmine.stoutner.com/issues/744
authorSoren Stoutner <soren@stoutner.com>
Fri, 6 Aug 2021 05:05:31 +0000 (22:05 -0700)
committerSoren Stoutner <soren@stoutner.com>
Fri, 6 Aug 2021 05:05:31 +0000 (22:05 -0700)
36 files changed:
app/build.gradle
app/src/main/assets/de/about_changelog.html
app/src/main/assets/en/about_changelog.html
app/src/main/assets/es/about_changelog.html
app/src/main/assets/fr/about_changelog.html
app/src/main/assets/fr/about_licenses.html
app/src/main/assets/it/about_changelog.html
app/src/main/assets/pt-rBR/about_changelog.html
app/src/main/assets/ru/about_changelog.html
app/src/main/assets/tr/about_changelog.html
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/adapters/HistoryArrayAdapter.java
app/src/main/java/com/stoutner/privacybrowser/adapters/PinnedMismatchPagerAdapter.kt
app/src/main/java/com/stoutner/privacybrowser/asynctasks/GetHostIpAddresses.java
app/src/main/java/com/stoutner/privacybrowser/asynctasks/PrepareSaveDialog.java
app/src/main/java/com/stoutner/privacybrowser/dataclasses/History.kt [new file with mode: 0644]
app/src/main/java/com/stoutner/privacybrowser/dataclasses/PendingDialog.kt [new file with mode: 0644]
app/src/main/java/com/stoutner/privacybrowser/definitions/History.java [deleted file]
app/src/main/java/com/stoutner/privacybrowser/definitions/PendingDialog.java [deleted file]
app/src/main/java/com/stoutner/privacybrowser/dialogs/HttpAuthenticationDialog.kt
app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt
app/src/main/java/com/stoutner/privacybrowser/dialogs/UrlHistoryDialog.kt
app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.kt
app/src/main/java/com/stoutner/privacybrowser/helpers/CheckPinnedMismatchHelper.java
app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.java [deleted file]
app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.kt [new file with mode: 0644]
app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java [deleted file]
app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt [new file with mode: 0644]
app/src/main/java/com/stoutner/privacybrowser/views/NoSwipeViewPager.java [deleted file]
app/src/main/java/com/stoutner/privacybrowser/views/NoSwipeViewPager.kt [new file with mode: 0644]
app/src/main/java/com/stoutner/privacybrowser/views/WrapVerticalContentViewPager.java [deleted file]
app/src/main/java/com/stoutner/privacybrowser/views/WrapVerticalContentViewPager.kt [new file with mode: 0644]
build.gradle
fastlane/metadata/android/fr-FR/changelogs/55.txt
fastlane/metadata/android/fr-FR/changelogs/56.txt
gradle/wrapper/gradle-wrapper.properties

index 035f2fcc7f0fa527e3726af170e68302409b7106..b75f2115b828769bc300d23b24dfcc79e96d4d64 100644 (file)
@@ -72,10 +72,10 @@ dependencies {
     // Include the following AndroidX libraries.
     implementation 'androidx.arch.core:core-common:2.1.0'
     implementation 'androidx.arch.core:core-runtime:2.1.0'
-    implementation 'androidx.appcompat:appcompat:1.3.0'
+    implementation 'androidx.appcompat:appcompat:1.3.1'
     implementation 'androidx.cardview:cardview:1.0.0'
     implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
-    implementation 'androidx.core:core-ktx:1.5.0'
+    implementation 'androidx.core:core-ktx:1.6.0'
     implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
     implementation 'androidx.preference:preference-ktx:1.1.1'
     implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
@@ -83,10 +83,10 @@ dependencies {
     implementation 'androidx.webkit:webkit:1.4.0'
 
     // Include the Kotlin standard libraries.  This should be the same version number listed in project build.gradle.
-    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.20'
+    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21'
 
     // Include the Google material library.
-    implementation 'com.google.android.material:material:1.3.0'
+    implementation 'com.google.android.material:material:1.4.0'
 
     // Only compile AdMob ads for the free flavor.
     freeImplementation 'com.google.android.gms:play-services-ads:20.2.0'
index df9d6a0f641fcbd0344398f348ee28dcf37f13bc..2e0e99838a06a933b103ca8c814588cbbd2c9d98 100644 (file)
@@ -33,8 +33,8 @@
     </head>
 
     <body>
-        <h3>3.8.1 (version code 56)</h3>
-        <p>29. Juni 2021 - Mindest-API 19, Ziel-API 30</p>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (version code 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29. Juni 2021</a> - Mindest-API 19, Ziel-API 30</p>
         <ul>
             <li><a href="https://redmine.stoutner.com/issues/722">Startpage</a> entfernt und <a href="https://redmine.stoutner.com/issues/577">Mojeek</a>
                 als Standard-Homepage und -Suchmaschine eingerichtet.</li>
index 07e0655d1a2796ca4f5a9768b54711fee59ba5f1..1469bc5232b4a5bf4cf26626a4ca9f7df997ae16 100644 (file)
@@ -27,8 +27,8 @@
     </head>
 
     <body>
-        <h3>3.8.1 (version code 56)</h3>
-        <p>29 June 2021 - minimum API 19, target API 30</p>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (version code 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29 June 2021</a> - minimum API 19, target API 30</p>
         <ul>
             <li>Remove <a href="https://redmine.stoutner.com/issues/722">Startpage</a> and make <a href="https://redmine.stoutner.com/issues/577">Mojeek</a> the default homepage and search engine.</li>
             <li>Invert the <a href="https://redmine.stoutner.com/issues/728">navigation menu</a> when the app bar is on the bottom.</li>
index fdc75815b6f9bb0a6a062f442a42728b88e4781a..ce41d6b473720d65eb8a1c2d20d42dc10aa46297 100644 (file)
@@ -29,8 +29,8 @@
     </head>
 
     <body>
-        <h3>3.8.1 (código de versión 56)</h3>
-        <p>29 de junio de 2021 - API mínimo 19, API dirigido 30</p>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (código de versión 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29 de junio de 2021</a> - API mínimo 19, API dirigido 30</p>
         <ul>
             <li>Eliminar <a href="https://redmine.stoutner.com/issues/722">Startpage</a> y hacer de <a href="https://redmine.stoutner.com/issues/577">Mojeek</a>
                 el motor de búsqueda y la página de inicio por defecto.</li>
index e36c9508d9ce759b7e109e49ff831ab316cf1e13..b8734d0c695f474f7d048e190ed7e8bf5f3da325 100644 (file)
     </head>
 
     <body>
-        <h3>3.8.1 (version du code 56)</h3>
-        <p>29 Juin 2021 - API minimale : 19, API optimale : 30</p>
-        <ul>
-            <li>Remove <a href="https://redmine.stoutner.com/issues/722">Startpage</a> and make <a href="https://redmine.stoutner.com/issues/577">Mojeek</a> the default homepage and search engine.</li>
-            <li>Invert the <a href="https://redmine.stoutner.com/issues/728">navigation menu</a> when the app bar is on the bottom.</li>
-            <li>Show the <a href="https://redmine.stoutner.com/issues/729">bottom app bar</a> when a new tab loads.</li>
-            <li>Limit <a href="https://redmine.stoutner.com/issues/731">content intent filters</a> to text, images, and MHT files.</li>
-            <li>Fix some <a href="https://redmine.stoutner.com/issues/725">rare</a> <a href="https://redmine.stoutner.com/issues/730">crashes</a>.</li>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (version du code 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29 Juin 2021</a> - API minimale : 19, API optimale : 30</p>
+        <ul>
+            <li>Suppression de <a href="https://redmine.stoutner.com/issues/722">Startpage</a> et passage de <a href="https://redmine.stoutner.com/issues/577">Mojeek</a>
+                en page d'accueil et moteur de recherche par défaut.</li>
+            <li>Inversion du <a href="https://redmine.stoutner.com/issues/728">menu de navigation</a> lorsque la barre des apps est en bas.</li>
+            <li>Affichage de la <a href="https://redmine.stoutner.com/issues/729">barre d'apps inférieure</a> lorsqu'un nouvel onglet se charge.</li>
+            <li>Limitation <a href="https://redmine.stoutner.com/issues/731">des filtres d'intention de contenu</a> au texte, aux images et aux fichiers MHT.</li>
+            <li>Correction de certains <a href="https://redmine.stoutner.com/issues/725">rare</a> <a href="https://redmine.stoutner.com/issues/730">crashs</a>.</li>
             <li>Traduction française mise à jour fournie par <a href="mailto:kevinliste@framalistes.org">Kévin L</a>.</li>
         </ul>
 
         <h3><a href="https://www.stoutner.com/privacy-browser-3-8/">3.8</a> (version du code 55)</h3>
         <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=1650cd6eff9ef807a84263328cb73e755250e3af">24 Mai 2021</a> - API minimale : 19, API optimale : 30</p>
         <ul>
-            <li>Add an option to <a href="https://redmine.stoutner.com/issues/143">move the app bar to the bottom</a>.</li>
-            <li>Reimplement the <a href="https://redmine.stoutner.com/issues/677">saving of web archives</a>.</li>
-            <li>Reimplement the option to use an <a href="https://redmine.stoutner.com/issues/698">external app to download files</a>.</li>
-            <li>Add fallbacks to open <a href="https://redmine.stoutner.com/issues/671">alternate download managers</a>.</li>
-            <li>Add <a href="https://redmine.stoutner.com/issues/713">Monocles</a> to the list of search engines.</li>
-            <li>Remove <a href="https://redmine.stoutner.com/issues/668">Do Not Track</a> and <a href="https://redmine.stoutner.com/issues/601">third-party cookies</a>.</li>
-            <li>Offer to open <a href="https://redmine.stoutner.com/issues/629">content</a> <a href="https://redmine.stoutner.com/issues/630">URLs</a> shared by other apps.</li>
-            <li>Handle <a href="https://redmine.stoutner.com/issues/361">content URLs</a> and <a href="https://redmine.stoutner.com/issues/552">untrusted SSL certificates</a> in View Source.</li>
-            <li>Fix <a href="https://redmine.stoutner.com/issues/709">UI freezing</a> while downloading on some devices.</li>
-            <li>Fix a <a href="https://redmine.stoutner.com/issues/699">few</a> <a href="https://redmine.stoutner.com/issues/694">rare</a> <a href="https://redmine.stoutner.com/issues/701">crashes</a>.</li>
-            <li>Make <a href="https://redmine.stoutner.com/issues/622">minor</a> <a href="https://redmine.stoutner.com/issues/644">improvements</a> to the
-                <a href="https://redmine.stoutner.com/issues/659">user</a> <a href="https://redmine.stoutner.com/issues/656">interface</a>.</li>
+            <li>Ajout d'une option pour <a href="https://redmine.stoutner.com/issues/143">déplacer la barre des apps en bas</a>.</li>
+            <li>Ré-implémentation de la <a href="https://redmine.stoutner.com/issues/677">sauvegarde des archives web</a>.</li>
+            <li>Ré-implémentation de l'option d'utiliser une <a href="https://redmine.stoutner.com/issues/698">application externe pour télécharger des fichiers</a>.</li>
+            <li>Ajout de fallbacks pour ouvrir <a href="https://redmine.stoutner.com/issues/671">des gestionnaires de téléchargement alternatifs</a>.</li>
+            <li>Ajout de <a href="https://redmine.stoutner.com/issues/713">Monocles</a> à la liste des moteurs de recherche.</li>
+            <li>Suppression de <a href="https://redmine.stoutner.com/issues/668">Do Not Track</a> et <a href="https://redmine.stoutner.com/issues/601">des cookies tiers</a>.</li>
+            <li>Offrir d'ouvrir les <a href="https://redmine.stoutner.com/issues/629">contenus</a> <a href="https://redmine.stoutner.com/issues/630">d'URLs</a> partagés par d'autres apps.</li>
+            <li>Gestion des <a href="https://redmine.stoutner.com/issues/361">URLs de contenu</a> et <a href="https://redmine.stoutner.com/issues/552">des certificats SSL non fiables</a> dans View Source.</li>
+            <li>Correction d'un <a href="https://redmine.stoutner.com/issues/709">gel de l'interface utilisateur</a> lors du téléchargement sur certains appareils.</li>
+            <li>Correction de <a href="https://redmine.stoutner.com/issues/699">quelques</a> <a href="https://redmine.stoutner.com/issues/694">rares</a>
+                <a href="https://redmine.stoutner.com/issues/701">crash</a>.</li>
+            <li>Quelques <a href="https://redmine.stoutner.com/issues/622">améliorations</a> <a href="https://redmine.stoutner.com/issues/644">mineures</a>
+                <a href="https://redmine.stoutner.com/issues/659">de l'interface</a> <a href="https://redmine.stoutner.com/issues/656">utilisateur</a>.</li>
             <li>Traduction française mise à jour fournie par <a href="mailto:kevinliste@framalistes.org">Kévin L</a>.</li>
             <li>Traduction portugaise brésilienne mise à jour fournie par <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>.</li>
             <li>Traduction allemande mise à jour fournie par Bernhard G. Keller.</li>
index 780986df7d7bc4294e6cbf549e94326222cd53bc..6454007b9f065a8e7a3565fdd10cfd15b875ae5e 100644 (file)
@@ -1,7 +1,7 @@
 <!--
   Copyright © 2016-2021 Soren Stoutner <soren@stoutner.com>.
 
-  Translation 2019-2020 Kévin L. <kevinliste@framalistes.org>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+  Translation 2019-2021 Kévin L. <kevinliste@framalistes.org>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
   This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
 
@@ -54,7 +54,7 @@
             et le code du <a href="https://mvnrepository.com/artifact/com.google.android.material/material">référentiel Google Material Maven</a>,
             publiés sous la <a href="https://www.apache.org/licenses/LICENSE-2.0">Licence Apache 2.0</a>.</p>
 
-        <p>La version gratuite de Privacy Browser repose sur les <a href="https://developers.google.com/admob/android/quick-start">Google’s AdMob</a>,
+        <p>La version gratuite de Privacy Browser repose sur <a href="https://developers.google.com/admob/android/quick-start">AdMob de Google</a>,
             publié sous la <a href="https://developer.android.com/studio/terms">licence du kit de développement logiciel Android</a>.</p>
 
         <h3>Classes</h3>
index eb43e69dff222d546503587d8363fe9cb64e62e2..33db78899233261fe977d744392e198da8ca37ef 100644 (file)
@@ -29,8 +29,8 @@
     </head>
 
     <body>
-        <h3>3.8.1 (versione codice 56)</h3>
-        <p>29 Giugno 2021 - minima API 19, target API 30</p>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (versione codice 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29 Giugno 2021</a> - minima API 19, target API 30</p>
         <ul>
             <li>Rimozione di <a href="https://redmine.stoutner.com/issues/722">Startpage</a> e sostituzione con <a href="https://redmine.stoutner.com/issues/577">Mojeek</a>
                 come pagina iniziale e motore di ricerca predefinito.</li>
index 1f39fe43e949d0edd16509813d0f5ae81f1cd9d5..8480db79bcd37c4bad23a7bb71ca66719342471a 100644 (file)
@@ -29,8 +29,8 @@
     </head>
 
     <body>
-        <h3>3.8.1 (código da versão 56)</h3>
-        <p>29 June 2021 - minimum API 19, target API 30</p>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (código da versão 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29 June 2021</a> - minimum API 19, target API 30</p>
         <ul>
             <li>Remove <a href="https://redmine.stoutner.com/issues/722">Startpage</a> and make <a href="https://redmine.stoutner.com/issues/577">Mojeek</a> the default homepage and search engine.</li>
             <li>Invert the <a href="https://redmine.stoutner.com/issues/728">navigation menu</a> when the app bar is on the bottom.</li>
index b2874e67544ef234cba808b86e383429b3b5e00f..3208f7cd6de61160971101849b196f5e974e7b78 100644 (file)
@@ -27,8 +27,8 @@
     </head>
 
     <body>
-        <h3>3.8.1 (код версии 56)</h3>
-        <p>29 июня 2021 года - минимальный API 19, целевой API 30</p>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (код версии 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29 июня 2021 года</a> - минимальный API 19, целевой API 30</p>
         <ul>
             <li>Удалена <a href="https://redmine.stoutner.com/issues/722">Startpage</a> и сделана <a href="https://redmine.stoutner.com/issues/577">Mojeek</a>
                 домашней страницей и поисковой системой по умолчанию.</li>
index d9ab9e237f14573e639455f4d09e3aecbdb98838..d056048b055ddc6aa74f297b1f79e3613808f75d 100644 (file)
@@ -27,8 +27,8 @@
     </head>
 
     <body>
-        <h3>3.8.1 (version code 56)</h3>
-        <p>29 June 2021 - minimum API 19, target API 30</p>
+        <h3><a href="https://www.stoutner.com/privacy-browser-3-8-1/">3.8.1</a> (version code 56)</h3>
+        <p><a href="https://gitweb.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=bda37dc9784e900cb64b87af3e221e11320d9d01">29 June 2021</a> - minimum API 19, target API 30</p>
         <ul>
             <li>Remove <a href="https://redmine.stoutner.com/issues/722">Startpage</a> and make <a href="https://redmine.stoutner.com/issues/577">Mojeek</a> the default homepage and search engine.</li>
             <li>Invert the <a href="https://redmine.stoutner.com/issues/728">navigation menu</a> when the app bar is on the bottom.</li>
index d2881d7ebe8887c6d299ca1ec9b1b55cdc6b7e44..16dfcaaf3e20164e325af872dfa4864d99d24772 100644 (file)
@@ -127,7 +127,7 @@ import com.stoutner.privacybrowser.asynctasks.PopulateBlocklists;
 import com.stoutner.privacybrowser.asynctasks.PrepareSaveDialog;
 import com.stoutner.privacybrowser.asynctasks.SaveUrl;
 import com.stoutner.privacybrowser.asynctasks.SaveWebpageImage;
-import com.stoutner.privacybrowser.definitions.PendingDialog;
+import com.stoutner.privacybrowser.dataclasses.PendingDialog;
 import com.stoutner.privacybrowser.dialogs.AdConsentDialog;
 import com.stoutner.privacybrowser.dialogs.CreateBookmarkDialog;
 import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog;
@@ -376,9 +376,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private MenuItem optionsFontSizeMenuItem;
     private MenuItem optionsAddOrEditDomainMenuItem;
 
-    @Override
-    // Remove the warning about needing to override `performClick()` when using an `OnTouchListener` with `WebView`.
+    // Remove the warning about needing to override `performClick()` when using an `OnTouchListener` with WebView.
     @SuppressLint("ClickableViewAccessibility")
+    @Override
     protected void onCreate(Bundle savedInstanceState) {
         // Run the default commands.
         super.onCreate(savedInstanceState);
@@ -631,7 +631,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
 
                     // Reset the current domain name so the domain settings will be reapplied.
-                    nestedScrollWebView.resetCurrentDomainName();
+                    nestedScrollWebView.setCurrentDomainName("");
 
                     // Reapply the domain settings if the URL is not null, which can happen if an empty tab is active when returning from settings.
                     if (nestedScrollWebView.getUrl() != null) {
@@ -969,13 +969,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Set the status of the menu item checkboxes.
             optionsDomStorageMenuItem.setChecked(currentWebView.getSettings().getDomStorageEnabled());
             optionsSaveFormDataMenuItem.setChecked(currentWebView.getSettings().getSaveFormData());  // Form data can be removed once the minimum API >= 26.
-            optionsEasyListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST));
-            optionsEasyPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY));
-            optionsFanboysAnnoyanceListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST));
-            optionsFanboysSocialBlockingListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST));
-            optionsUltraListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST));
-            optionsUltraPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY));
-            optionsBlockAllThirdPartyRequestsMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS));
+            optionsEasyListMenuItem.setChecked(currentWebView.getEasyListEnabled());
+            optionsEasyPrivacyMenuItem.setChecked(currentWebView.getEasyPrivacyEnabled());
+            optionsFanboysAnnoyanceListMenuItem.setChecked(currentWebView.getFanboysAnnoyanceListEnabled());
+            optionsFanboysSocialBlockingListMenuItem.setChecked(currentWebView.getFanboysSocialBlockingListEnabled());
+            optionsUltraListMenuItem.setChecked(currentWebView.getUltraListEnabled());
+            optionsUltraPrivacyMenuItem.setChecked(currentWebView.getUltraPrivacyEnabled());
+            optionsBlockAllThirdPartyRequestsMenuItem.setChecked(currentWebView.getBlockAllThirdPartyRequests());
             optionsSwipeToRefreshMenuItem.setChecked(currentWebView.getSwipeToRefresh());
             optionsWideViewportMenuItem.setChecked(currentWebView.getSettings().getUseWideViewPort());
             optionsDisplayImagesMenuItem.setChecked(currentWebView.getSettings().getLoadsImagesAutomatically());
@@ -1393,10 +1393,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             return true;
         } else if (menuItemId == R.id.easylist) {  // EasyList.
             // Toggle the EasyList status.
-            currentWebView.enableBlocklist(NestedScrollWebView.EASYLIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST));
+            currentWebView.setEasyListEnabled(!currentWebView.getEasyListEnabled());
 
             // Update the menu checkbox.
-            menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST));
+            menuItem.setChecked(currentWebView.getEasyListEnabled());
 
             // Reload the current WebView.
             currentWebView.reload();
@@ -1405,10 +1405,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             return true;
         } else if (menuItemId == R.id.easyprivacy) {  // EasyPrivacy.
             // Toggle the EasyPrivacy status.
-            currentWebView.enableBlocklist(NestedScrollWebView.EASYPRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY));
+            currentWebView.setEasyPrivacyEnabled(!currentWebView.getEasyPrivacyEnabled());
 
             // Update the menu checkbox.
-            menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY));
+            menuItem.setChecked(currentWebView.getEasyPrivacyEnabled());
 
             // Reload the current WebView.
             currentWebView.reload();
@@ -1417,13 +1417,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             return true;
         } else if (menuItemId == R.id.fanboys_annoyance_list) {  // Fanboy's Annoyance List.
             // Toggle Fanboy's Annoyance List status.
-            currentWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST));
+            currentWebView.setFanboysAnnoyanceListEnabled(!currentWebView.getFanboysAnnoyanceListEnabled());
 
             // Update the menu checkbox.
-            menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST));
+            menuItem.setChecked(currentWebView.getFanboysAnnoyanceListEnabled());
 
             // Update the status of Fanboy's Social Blocking List.
-            optionsFanboysSocialBlockingListMenuItem.setEnabled(!currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST));
+            optionsFanboysSocialBlockingListMenuItem.setEnabled(!currentWebView.getFanboysAnnoyanceListEnabled());
 
             // Reload the current WebView.
             currentWebView.reload();
@@ -1432,10 +1432,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             return true;
         } else if (menuItemId == R.id.fanboys_social_blocking_list) {  // Fanboy's Social Blocking List.
             // Toggle Fanboy's Social Blocking List status.
-            currentWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST));
+            currentWebView.setFanboysSocialBlockingListEnabled(!currentWebView.getFanboysSocialBlockingListEnabled());
 
             // Update the menu checkbox.
-            menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST));
+            menuItem.setChecked(currentWebView.getFanboysSocialBlockingListEnabled());
 
             // Reload the current WebView.
             currentWebView.reload();
@@ -1444,10 +1444,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             return true;
         } else if (menuItemId == R.id.ultralist) {  // UltraList.
             // Toggle the UltraList status.
-            currentWebView.enableBlocklist(NestedScrollWebView.ULTRALIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST));
+            currentWebView.setUltraListEnabled(!currentWebView.getUltraListEnabled());
 
             // Update the menu checkbox.
-            menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST));
+            menuItem.setChecked(currentWebView.getUltraListEnabled());
 
             // Reload the current WebView.
             currentWebView.reload();
@@ -1456,10 +1456,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             return true;
         } else if (menuItemId == R.id.ultraprivacy) {  // UltraPrivacy.
             // Toggle the UltraPrivacy status.
-            currentWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY));
+            currentWebView.setUltraPrivacyEnabled(!currentWebView.getUltraPrivacyEnabled());
 
             // Update the menu checkbox.
-            menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY));
+            menuItem.setChecked(currentWebView.getUltraPrivacyEnabled());
 
             // Reload the current WebView.
             currentWebView.reload();
@@ -1468,10 +1468,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             return true;
         } else if (menuItemId == R.id.block_all_third_party_requests) {  // Block all third-party requests.
             //Toggle the third-party requests blocker status.
-            currentWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, !currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS));
+            currentWebView.setBlockAllThirdPartyRequests(!currentWebView.getBlockAllThirdPartyRequests());
 
             // Update the menu checkbox.
-            menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS));
+            menuItem.setChecked(currentWebView.getBlockAllThirdPartyRequests());
 
             // Reload the current WebView.
             currentWebView.reload();
@@ -1839,6 +1839,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 domainsIntent.putExtra("load_domain", currentWebView.getDomainSettingsDatabaseId());
                 domainsIntent.putExtra("close_on_back", true);
                 domainsIntent.putExtra("current_url", currentWebView.getUrl());
+                domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
 
                 // Get the current certificate.
                 SslCertificate sslCertificate = currentWebView.getCertificate();
@@ -1866,12 +1867,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     domainsIntent.putExtra("ssl_end_date", endDateLong);
                 }
 
-                // Check to see if the current IP addresses have been received.
-                if (currentWebView.hasCurrentIpAddresses()) {
-                    // Add the current IP addresses to the intent.
-                    domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
-                }
-
                 // Make it so.
                 startActivity(domainsIntent);
             } else {  // Add a new domain.
@@ -1895,6 +1890,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 domainsIntent.putExtra("load_domain", newDomainDatabaseId);
                 domainsIntent.putExtra("close_on_back", true);
                 domainsIntent.putExtra("current_url", currentWebView.getUrl());
+                domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
 
                 // Get the current certificate.
                 SslCertificate sslCertificate = currentWebView.getCertificate();
@@ -1922,12 +1918,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     domainsIntent.putExtra("ssl_end_date", endDateLong);
                 }
 
-                // Check to see if the current IP addresses have been received.
-                if (currentWebView.hasCurrentIpAddresses()) {
-                    // Add the current IP addresses to the intent.
-                    domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
-                }
-
                 // Make it so.
                 startActivity(domainsIntent);
             }
@@ -2015,7 +2005,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             Intent requestsIntent = new Intent(this, RequestsActivity.class);
 
             // Add the block third-party requests status to the intent.
-            requestsIntent.putExtra("block_all_third_party_requests", currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS));
+            requestsIntent.putExtra("block_all_third_party_requests", currentWebView.getBlockAllThirdPartyRequests());
 
             // Make it so.
             startActivity(requestsIntent);
@@ -2073,6 +2063,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
             // Add the extra information to the intent.
             domainsIntent.putExtra("current_url", currentWebView.getUrl());
+            domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
 
             // Get the current certificate.
             SslCertificate sslCertificate = currentWebView.getCertificate();
@@ -2100,12 +2091,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 domainsIntent.putExtra("ssl_end_date", endDateLong);
             }
 
-            // Check to see if the current IP addresses have been received.
-            if (currentWebView.hasCurrentIpAddresses()) {
-                // Add the current IP addresses to the intent.
-                domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
-            }
-
             // Make it so.
             startActivity(domainsIntent);
         } else if (menuItemId == R.id.settings) {  // Settings.
@@ -3263,7 +3248,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                                 loadUrl(nestedScrollWebView, waitingForProxyUrlString);
 
                                 // Reset the waiting for proxy URL string.
-                                nestedScrollWebView.resetWaitingForProxyUrlString();
+                                nestedScrollWebView.setWaitingForProxyUrlString("");
                             } else {  // No URL is waiting to be loaded.
                                 // Reload the existing URL.
                                 nestedScrollWebView.reload();
@@ -3338,7 +3323,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             @Override
             public void onTabReselected(TabLayout.Tab tab) {
                 // Instantiate the View SSL Certificate dialog.
-                DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId());
+                DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId(), currentWebView.getFavoriteOrDefaultIcon());
 
                 // Display the View SSL Certificate dialog.
                 viewSslCertificateDialogFragment.show(getSupportFragmentManager(), getString(R.string.view_ssl_certificate));
@@ -3791,7 +3776,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
             // Clear any pinned SSL certificate or IP addresses.
             nestedScrollWebView.clearPinnedSslCertificate();
-            nestedScrollWebView.clearPinnedIpAddresses();
+            nestedScrollWebView.setPinnedIpAddresses("");
 
             // Reset the favorite icon if specified.
             if (resetTab) {
@@ -3911,19 +3896,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 nestedScrollWebView.getSettings().setDomStorageEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1);
                 // Form data can be removed once the minimum API >= 26.
                 boolean saveFormData = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1);
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYLIST,
-                        currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST)) == 1);
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYPRIVACY,
-                        currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY)) == 1);
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST,
-                        currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1);
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST,
-                        currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)) == 1);
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRALIST, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST)) == 1);
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY,
-                        currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY)) == 1);
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS,
-                        currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1);
+                nestedScrollWebView.setEasyListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST)) == 1);
+                nestedScrollWebView.setEasyPrivacyEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY)) == 1);
+                nestedScrollWebView.setFanboysAnnoyanceListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1);
+                nestedScrollWebView.setFanboysSocialBlockingListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(
+                        DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)) == 1);
+                nestedScrollWebView.setUltraListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST)) == 1);
+                nestedScrollWebView.setUltraPrivacyEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY)) == 1);
+                nestedScrollWebView.setBlockAllThirdPartyRequests(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1);
                 String userAgentName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
                 int fontSize = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
                 int swipeToRefreshInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
@@ -3937,31 +3917,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 String pinnedSslIssuedByCName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
                 String pinnedSslIssuedByOName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
                 String pinnedSslIssuedByUName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
+                Date pinnedSslStartDate = new Date(currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
+                Date pinnedSslEndDate = new Date(currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
                 boolean pinnedIpAddresses = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES)) == 1);
                 String pinnedHostIpAddresses = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
 
-                // Get the pinned SSL date longs.
-                long pinnedSslStartDateLong = currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE));
-                long pinnedSslEndDateLong = currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE));
-
-                // Define the pinned SSL date variables.
-                Date pinnedSslStartDate;
-                Date pinnedSslEndDate;
-
-                // Set the pinned SSL certificate start date to `null` if the saved date long is 0 because creating a new date results in an error if the input is 0.
-                if (pinnedSslStartDateLong == 0) {
-                    pinnedSslStartDate = null;
-                } else {
-                    pinnedSslStartDate = new Date(pinnedSslStartDateLong);
-                }
-
-                // Set the pinned SSL certificate end date to `null` if the saved date long is 0 because creating a new date results in an error if the input is 0.
-                if (pinnedSslEndDateLong == 0) {
-                    pinnedSslEndDate = null;
-                } else {
-                    pinnedSslEndDate = new Date(pinnedSslEndDateLong);
-                }
-
                 // Close the current host domain settings cursor.
                 currentDomainSettingsCursor.close();
 
@@ -4159,13 +4119,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 nestedScrollWebView.setAcceptCookies(sharedPreferences.getBoolean(getString(R.string.cookies_key), false));
                 nestedScrollWebView.getSettings().setDomStorageEnabled(sharedPreferences.getBoolean("dom_storage", false));
                 boolean saveFormData = sharedPreferences.getBoolean("save_form_data", false);  // Form data can be removed once the minimum API >= 26.
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYLIST, sharedPreferences.getBoolean("easylist", true));
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYPRIVACY, sharedPreferences.getBoolean("easyprivacy", true));
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST, sharedPreferences.getBoolean("fanboys_annoyance_list", true));
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST, sharedPreferences.getBoolean("fanboys_social_blocking_list", true));
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRALIST, sharedPreferences.getBoolean("ultralist", true));
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY, sharedPreferences.getBoolean("ultraprivacy", true));
-                nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, sharedPreferences.getBoolean("block_all_third_party_requests", false));
+                nestedScrollWebView.setEasyListEnabled(sharedPreferences.getBoolean("easylist", true));
+                nestedScrollWebView.setEasyPrivacyEnabled(sharedPreferences.getBoolean("easyprivacy", true));
+                nestedScrollWebView.setFanboysAnnoyanceListEnabled(sharedPreferences.getBoolean("fanboys_annoyance_list", true));
+                nestedScrollWebView.setFanboysSocialBlockingListEnabled(sharedPreferences.getBoolean("fanboys_social_blocking_list", true));
+                nestedScrollWebView.setUltraListEnabled(sharedPreferences.getBoolean("ultralist", true));
+                nestedScrollWebView.setUltraPrivacyEnabled(sharedPreferences.getBoolean("ultraprivacy", true));
+                nestedScrollWebView.setBlockAllThirdPartyRequests(sharedPreferences.getBoolean("block_all_third_party_requests", false));
 
                 // Apply the default cookie setting.
                 cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptCookies());
@@ -5204,6 +5164,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         }
     }
 
+    @SuppressLint("ClickableViewAccessibility")
     @Override
     public void initializeWebView(NestedScrollWebView nestedScrollWebView, int pageNumber, ProgressBar progressBar, String url, Boolean restoringState) {
         // Get a handle for the shared preferences.
@@ -5259,9 +5220,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Remove the lint warning below that the input method manager might be null.
         assert inputMethodManager != null;
 
-        // Initialize the favorite icon.
-        nestedScrollWebView.initializeFavoriteIcon();
-
         // Set the app bar scrolling.
         nestedScrollWebView.setNestedScrollingEnabled(sharedPreferences.getBoolean("scroll_app_bar", true));
 
@@ -5821,7 +5779,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 String currentDomain = currentBaseDomain;
 
                 // Nobody is happy when comparing null strings.
-                if ((currentBaseDomain != null) && (url != null)) {
+                if (url != null) {
                     // Convert the request URL to a URI.
                     Uri requestUri = Uri.parse(url);
 
@@ -5854,7 +5812,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 boolean webViewDisplayed = (webViewPagePosition == tabLayout.getSelectedTabPosition());
 
                 // Block third-party requests if enabled.
-                if (isThirdPartyRequest && nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)) {
+                if (isThirdPartyRequest && nestedScrollWebView.getBlockAllThirdPartyRequests()) {
                     // Add the result to the resource requests.
                     nestedScrollWebView.addResourceRequest(new String[]{BlocklistHelper.REQUEST_THIRD_PARTY, url});
 
@@ -5883,7 +5841,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Check UltraList if it is enabled.
-                if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST)) {
+                if (nestedScrollWebView.getUltraListEnabled()) {
                     // Check the URL against UltraList.
                     String[] ultraListResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, ultraList);
 
@@ -5923,7 +5881,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Check UltraPrivacy if it is enabled.
-                if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY)) {
+                if (nestedScrollWebView.getUltraPrivacyEnabled()) {
                     // Check the URL against UltraPrivacy.
                     String[] ultraPrivacyResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, ultraPrivacy);
 
@@ -5965,7 +5923,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Check EasyList if it is enabled.
-                if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST)) {
+                if (nestedScrollWebView.getEasyListEnabled()) {
                     // Check the URL against EasyList.
                     String[] easyListResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyList);
 
@@ -6002,7 +5960,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Check EasyPrivacy if it is enabled.
-                if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY)) {
+                if (nestedScrollWebView.getEasyPrivacyEnabled()) {
                     // Check the URL against EasyPrivacy.
                     String[] easyPrivacyResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyPrivacy);
 
@@ -6040,7 +5998,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Check Fanboy’s Annoyance List if it is enabled.
-                if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)) {
+                if (nestedScrollWebView.getFanboysAnnoyanceListEnabled()) {
                     // Check the URL against Fanboy's Annoyance List.
                     String[] fanboysAnnoyanceListResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, fanboysAnnoyanceList);
 
@@ -6077,7 +6035,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         whitelistResultStringArray = new String[] {fanboysAnnoyanceListResults[0], fanboysAnnoyanceListResults[1], fanboysAnnoyanceListResults[2], fanboysAnnoyanceListResults[3],
                                 fanboysAnnoyanceListResults[4], fanboysAnnoyanceListResults[5]};
                     }
-                } else if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST)) {  // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled.
+                } else if (nestedScrollWebView.getFanboysSocialBlockingListEnabled()) {  // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled.
                     // Check the URL against Fanboy's Annoyance List.
                     String[] fanboysSocialListResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, fanboysSocialList);
 
@@ -6185,7 +6143,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Reset the list of host IP addresses.
-                nestedScrollWebView.clearCurrentIpAddresses();
+                nestedScrollWebView.setCurrentIpAddresses("");
 
                 // Get a URI for the current URL.
                 Uri currentUri = Uri.parse(url);
index 1d60ae208c114f48d345e552bffb5ab54af9b207..33fa6e5af0e5a61bc538db626ecd7e3a2a8be24c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2016-2019,2021 Soren Stoutner <soren@stoutner.com>.
  *
  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
  *
@@ -31,7 +31,7 @@ import android.widget.TextView;
 import androidx.annotation.NonNull;
 
 import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.definitions.History;
+import com.stoutner.privacybrowser.dataclasses.History;
 
 import java.util.ArrayList;
 
index 6156533a72d2d4d1d50e4d846a5e58c4109bb1ab..f955fb8483afc86f61f0d256c23e1d4150913074 100644 (file)
@@ -131,7 +131,7 @@ class PinnedMismatchPagerAdapter(private val context: Context, private val layou
         }
 
         // Get the pinned SSL certificate.
-        val pinnedSslCertificateArrayList = nestedScrollWebView.pinnedSslCertificate
+        val pinnedSslCertificateArrayList = nestedScrollWebView.getPinnedSslCertificate()
 
         // Extract the arrays from the array list.
         val pinnedSslCertificateStringArray = pinnedSslCertificateArrayList[0] as Array<*>
@@ -222,7 +222,7 @@ class PinnedMismatchPagerAdapter(private val context: Context, private val layou
         domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length, domainNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
 
         // Color coordinate the IP addresses if they are pinned.
-        if (nestedScrollWebView.hasPinnedIpAddresses()) {
+        if (!nestedScrollWebView.pinnedIpAddresses.equals("")) {
             if (nestedScrollWebView.currentIpAddresses == nestedScrollWebView.pinnedIpAddresses) {
                 ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length, ipAddressesStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
             } else {
index 96a223f0e6eba42bb63b018e8d9be837105353c0..af90fed0eb3a47119e0bd0a2cd8dd889747c7092 100644 (file)
@@ -101,7 +101,7 @@ public class GetHostIpAddresses extends AsyncTask<String, Void, String> {
         nestedScrollWebView.setCurrentIpAddresses(ipAddresses);
 
         // Checked for pinned mismatches if there is pinned information and it is not ignored.
-        if ((nestedScrollWebView.hasPinnedSslCertificate() || nestedScrollWebView.hasPinnedIpAddresses()) && !nestedScrollWebView.ignorePinnedDomainInformation()) {
+        if ((nestedScrollWebView.hasPinnedSslCertificate() || !nestedScrollWebView.getPinnedIpAddresses().equals("")) && !nestedScrollWebView.getIgnorePinnedDomainInformation()) {
             CheckPinnedMismatchHelper.checkPinnedMismatch(activity, fragmentManager, nestedScrollWebView);
         }
     }
index 93bd110e7d5ad5edb4d8a1a23f9adf9f0b58cef1..28c3e65606f366cb5d8121785100ceef4333469d 100644 (file)
@@ -31,7 +31,7 @@ import androidx.fragment.app.FragmentManager;
 
 import com.stoutner.privacybrowser.R;
 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
-import com.stoutner.privacybrowser.definitions.PendingDialog;
+import com.stoutner.privacybrowser.dataclasses.PendingDialog;
 import com.stoutner.privacybrowser.dialogs.SaveWebpageDialog;
 import com.stoutner.privacybrowser.helpers.ProxyHelper;
 
@@ -97,7 +97,7 @@ public class PrepareSaveDialog extends AsyncTask<String, Void, String[]> {
             String base64DataString = urlWithoutData.substring(urlWithoutData.indexOf(",") + 1);
 
             // Calculate the file size of the data URL.  Each Base64 character represents 6 bits.
-            formattedFileSize = NumberFormat.getInstance().format(base64DataString.length() * 3 / 4) + " " + context.getString(R.string.bytes);
+            formattedFileSize = NumberFormat.getInstance().format(base64DataString.length() * 3L / 4) + " " + context.getString(R.string.bytes);
 
             // Set the file name according to the MIME type.
             fileNameString = context.getString(R.string.file) + "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(urlMimeType);
diff --git a/app/src/main/java/com/stoutner/privacybrowser/dataclasses/History.kt b/app/src/main/java/com/stoutner/privacybrowser/dataclasses/History.kt
new file mode 100644 (file)
index 0000000..c6fd102
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2016-2017,2021 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.dataclasses
+
+import android.graphics.Bitmap
+
+// Define the history data class.  The `@JvmField` notation can be remove once all the code has migrated to Kotlin.
+data class History(@JvmField val favoriteIcon: Bitmap, @JvmField val url: String)
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/dataclasses/PendingDialog.kt b/app/src/main/java/com/stoutner/privacybrowser/dataclasses/PendingDialog.kt
new file mode 100644 (file)
index 0000000..3a35c45
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2021 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.dataclasses
+
+import androidx.fragment.app.DialogFragment
+
+// Define the pending dialogs data class.  The `@JvmField` notation can be remove once all the code has migrated to Kotlin.
+data class PendingDialog (@JvmField val dialogFragment: DialogFragment, @JvmField val tag: String)
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/definitions/History.java b/app/src/main/java/com/stoutner/privacybrowser/definitions/History.java
deleted file mode 100644 (file)
index 1b0e448..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright © 2016-2017,2021 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.definitions;
-
-import android.graphics.Bitmap;
-
-// Create a History object.
-public class History {
-    // Declare the class variables.
-    public final Bitmap favoriteIcon;
-    public final String url;
-
-    public History(Bitmap favoriteIcon, String url){
-        // Populate the class variables.
-        this.favoriteIcon = favoriteIcon;
-        this.url = url;
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/definitions/PendingDialog.java b/app/src/main/java/com/stoutner/privacybrowser/definitions/PendingDialog.java
deleted file mode 100644 (file)
index 719e599..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright © 2021 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.definitions;
-
-import androidx.fragment.app.DialogFragment;
-
-// Create a PendingDialogs object.
-public class PendingDialog {
-    // Declare the class variables.
-    public final DialogFragment dialogFragment;
-    public final String tag;
-
-    public PendingDialog(DialogFragment dialogFragment, String tag) {
-        // Populate the class variables.
-        this.dialogFragment = dialogFragment;
-        this.tag = tag;
-    }
-}
\ No newline at end of file
index 0e8a08db715a5dd60ae8c71593a5527434b4fc57..fc506f42fdaf9b71323dd319cc960e64cfc8ceb3 100644 (file)
@@ -120,18 +120,19 @@ class HttpAuthenticationDialog : DialogFragment() {
 
             // Set the close button listener.
             dialogBuilder.setNegativeButton(R.string.close) { _: DialogInterface?, _: Int ->
-                // Cancel the HTTP authentication request.
-                httpAuthHandler.cancel()
+                if (httpAuthHandler != null) {
+                    // Cancel the HTTP authentication request.
+                    httpAuthHandler.cancel()
 
-                // Reset the HTTP authentication handler.
-                nestedScrollWebView.resetHttpAuthHandler()
-            }// Set the proceed button listener.
+                    // Reset the HTTP authentication handler.
+                    nestedScrollWebView.resetHttpAuthHandler()
+                }
+            }
+
+            // Set the proceed button listener.
             dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int ->
                 // Send the login information
-                login(httpAuthHandler)
-
-                // Reset the HTTP authentication handler.
-                nestedScrollWebView.resetHttpAuthHandler()
+                login(httpAuthHandler, nestedScrollWebView)
             }
 
             // Create an alert dialog from the alert dialog builder.
@@ -193,7 +194,7 @@ class HttpAuthenticationDialog : DialogFragment() {
                 // Check the key code and event.
                 if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {  // The enter key was pressed.
                     // Send the login information.
-                    login(httpAuthHandler)
+                    login(httpAuthHandler, nestedScrollWebView)
 
                     // Manually dismiss the alert dialog.
                     alertDialog.dismiss()
@@ -210,7 +211,7 @@ class HttpAuthenticationDialog : DialogFragment() {
                 // Check the key code and event.
                 if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {  // The enter key was pressed.
                     // Send the login information.
-                    login(httpAuthHandler)
+                    login(httpAuthHandler, nestedScrollWebView)
 
                     // Manually dismiss the alert dialog.
                     alertDialog.dismiss()
@@ -249,8 +250,13 @@ class HttpAuthenticationDialog : DialogFragment() {
         }
     }
 
-    private fun login(httpAuthHandler: HttpAuthHandler) {
-        // Send the login information.
-        httpAuthHandler.proceed(usernameEditText.text.toString(), passwordEditText.text.toString())
+    private fun login(httpAuthHandler: HttpAuthHandler?, nestedScrollWebView: NestedScrollWebView) {
+        if (httpAuthHandler != null) {
+            // Send the login information.
+            httpAuthHandler.proceed(usernameEditText.text.toString(), passwordEditText.text.toString())
+
+            // Reset the HTTP authentication handler.
+            nestedScrollWebView.resetHttpAuthHandler()
+        }
     }
 }
\ No newline at end of file
index 8c1288f62888079910813734b7812148020c0cfc..d4ba4a74d9a8fe1a54378ee891c39f8df180fca2 100644 (file)
@@ -105,7 +105,7 @@ class PinnedMismatchDialog : DialogFragment() {
         val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
 
         // Get the favorite icon.
-        val favoriteIconBitmap = nestedScrollWebView.favoriteOrDefaultIcon
+        val favoriteIconBitmap = nestedScrollWebView.getFavoriteOrDefaultIcon()
 
         // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
         val defaultFavoriteIconDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.world)
@@ -163,7 +163,7 @@ class PinnedMismatchDialog : DialogFragment() {
             }
 
             // Update the IP addresses if they are pinned.
-            if (nestedScrollWebView.hasPinnedIpAddresses()) {
+            if (!nestedScrollWebView.pinnedIpAddresses.equals("")) {
                 // Update the pinned IP addresses in the domain database.
                 domainsDatabaseHelper.updatePinnedIpAddresses(nestedScrollWebView.domainSettingsDatabaseId, nestedScrollWebView. currentIpAddresses)
 
@@ -186,7 +186,7 @@ class PinnedMismatchDialog : DialogFragment() {
         // Set the proceed button listener.
         dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int ->
             // Do not check the pinned information for this domain again until the domain changes.
-            nestedScrollWebView.setIgnorePinnedDomainInformation(true)
+            nestedScrollWebView.ignorePinnedDomainInformation = true
         }
 
         // Create an alert dialog from the alert dialog builder.
index 9778954e0f1e9b3c156dc8a45a9faf3d14774241..fb2bcc5b8744fed60fee49cde95d18dc01592405 100644 (file)
@@ -40,7 +40,7 @@ import androidx.preference.PreferenceManager
 import com.stoutner.privacybrowser.R
 import com.stoutner.privacybrowser.activities.MainWebViewActivity
 import com.stoutner.privacybrowser.adapters.HistoryArrayAdapter
-import com.stoutner.privacybrowser.definitions.History
+import com.stoutner.privacybrowser.dataclasses.History
 import com.stoutner.privacybrowser.views.NestedScrollWebView
 
 // Define the class constants.
@@ -131,7 +131,7 @@ class UrlHistoryDialog : DialogFragment() {
             }
 
             // Store the favorite icon and the URL in history entry.
-            val historyEntry = History(favoriteIconBitmap, webBackForwardList.getItemAtIndex(i).url)
+            val historyEntry = History(favoriteIconBitmap!!, webBackForwardList.getItemAtIndex(i).url)
 
             // Add this history entry to the history array list.
             historyArrayList.add(historyEntry)
index b5b0dd275608cb4fb009f5a8c918dba08ebbe445..fbbfdabd20bd32e39670109c866896cdea310a31 100644 (file)
@@ -25,7 +25,6 @@ import android.content.res.Configuration
 import android.graphics.Bitmap
 import android.graphics.BitmapFactory
 import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.Drawable
 import android.net.Uri
 import android.os.Bundle
 import android.text.SpannableStringBuilder
@@ -50,8 +49,8 @@ import java.util.Date
 
 // Define the class constants.
 private const val WEBVIEW_FRAGMENT_ID = "webview_fragment_id"
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
 private const val HAS_SSL_CERTIFICATE = "has_ssl_certificate"
-private const val FAVORITE_ICON = "favorite_icon"
 private const val DOMAIN = "domain"
 private const val IP_ADDRESSES = "ip_addresses"
 private const val ISSUED_TO_CNAME = "issued_to_cname"
@@ -68,7 +67,6 @@ class ViewSslCertificateDialog : DialogFragment() {
     private var hasSslCertificate: Boolean = false
 
     // Declare the class variables.
-    private lateinit var favoriteIconDrawable: Drawable
     private lateinit var domainString: String
     private lateinit var ipAddresses: String
     private lateinit var issuedToCName: String
@@ -86,12 +84,22 @@ class ViewSslCertificateDialog : DialogFragment() {
     companion object {
         // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin.
         @JvmStatic
-        fun displayDialog(webViewFragmentId: Long): ViewSslCertificateDialog {
+        fun displayDialog(webViewFragmentId: Long, favoriteIconBitmap: Bitmap): ViewSslCertificateDialog {
             // Create an arguments bundle.
             val argumentsBundle = Bundle()
 
-            // Store the WebView fragment ID in the bundle.
+            // Create a favorite icon byte array output stream.
+            val favoriteIconByteArrayOutputStream = ByteArrayOutputStream()
+
+            // Convert the bitmap to a PNG and place it in the byte array output stream.  `0` is for lossless compression (the only option for a PNG).
+            favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream)
+
+            // Convert the favorite icon byte array output stream to a byte array.
+            val favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray()
+
+            // Store the arguments in the bundle.
             argumentsBundle.putLong(WEBVIEW_FRAGMENT_ID, webViewFragmentId)
+            argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
 
             // Create a new instance of the view SSL certificate dialog.
             val viewSslCertificateDialog = ViewSslCertificateDialog()
@@ -130,9 +138,6 @@ class ViewSslCertificateDialog : DialogFragment() {
             // Store the status of the SSL certificate.
             hasSslCertificate = sslCertificate != null
 
-            // Create a drawable version of the favorite icon.
-            favoriteIconDrawable = BitmapDrawable(resources, nestedScrollWebView.favoriteOrDefaultIcon)
-
             // Populate the certificate class variables if the webpage has an SSL certificate.
             if (hasSslCertificate) {
                 // Convert the URL to a URI.
@@ -157,13 +162,6 @@ class ViewSslCertificateDialog : DialogFragment() {
         } else {  // The dialog has been restarted.
             // Get the data from the saved instance state.
             hasSslCertificate = savedInstanceState.getBoolean(HAS_SSL_CERTIFICATE)
-            val favoriteIconByteArray = savedInstanceState.getByteArray(FAVORITE_ICON)!!
-
-            // Convert the favorite icon byte array to a bitmap.
-            val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
-
-            // Create a drawable version of the favorite icon.
-            favoriteIconDrawable = BitmapDrawable(resources, favoriteIconBitmap)
 
             // Populate the certificate class variables if the webpage has an SSL certificate.
             if (hasSslCertificate) {
@@ -181,6 +179,15 @@ class ViewSslCertificateDialog : DialogFragment() {
             }
         }
 
+        // Get the favorite icon byte array from the arguments.
+        val favoriteIconByteArray = requireArguments().getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
+
+        // Convert the favorite icon byte array to a bitmap.
+        val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
+
+        // Create a drawable version of the favorite icon.
+        val favoriteIconDrawable = BitmapDrawable(resources, favoriteIconBitmap)
+
         // Set the icon.
         dialogBuilder.setIcon(favoriteIconDrawable)
 
@@ -372,24 +379,8 @@ class ViewSslCertificateDialog : DialogFragment() {
         // Run the default commands.
         super.onSaveInstanceState(savedInstanceState)
 
-        // Get the favorite icon bitmap drawable.
-        val favoriteIconBitmapDrawable = favoriteIconDrawable as BitmapDrawable
-
-        // Get the favorite icon bitmap.
-        val favoriteIconBitmap = favoriteIconBitmapDrawable.bitmap
-
-        // Create a favorite icon byte array output stream.
-        val favoriteIconByteArrayOutputStream = ByteArrayOutputStream()
-
-        // Convert the bitmap to a PNG and place it in the byte array output stream.  `0` is for lossless compression (the only option for a PNG).
-        favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream)
-
-        // Convert the favorite icon byte array output stream to a byte array.
-        val favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray()
-
         // Save the common class variables.
         savedInstanceState.putBoolean(HAS_SSL_CERTIFICATE, hasSslCertificate)
-        savedInstanceState.putByteArray(FAVORITE_ICON, favoriteIconByteArray)
 
         // Save the SSL certificate strings if they exist.
         if (hasSslCertificate) {
index 9deff4ee91047f6913a93d92f872f1ccb87d3642..64fd40f462ab1f4a71fb4c05d20e747c5c58527f 100644 (file)
@@ -27,7 +27,7 @@ import androidx.fragment.app.FragmentManager;
 
 import com.stoutner.privacybrowser.R;
 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
-import com.stoutner.privacybrowser.definitions.PendingDialog;
+import com.stoutner.privacybrowser.dataclasses.PendingDialog;
 import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog;
 import com.stoutner.privacybrowser.views.NestedScrollWebView;
 
@@ -117,7 +117,7 @@ public class CheckPinnedMismatchHelper {
         }
 
         // Check to see if the pinned information matches the current information.
-        if ((nestedScrollWebView.hasPinnedIpAddresses() && !nestedScrollWebView.getCurrentIpAddresses().equals(nestedScrollWebView.getPinnedIpAddresses())) ||
+        if ((!nestedScrollWebView.getPinnedIpAddresses().equals("") && !nestedScrollWebView.getCurrentIpAddresses().equals(nestedScrollWebView.getPinnedIpAddresses())) ||
                 (nestedScrollWebView.hasPinnedSslCertificate() && (!currentWebsiteIssuedToCName.equals(pinnedSslIssuedToCName) ||
                 !currentWebsiteIssuedToOName.equals(pinnedSslIssuedToOName) || !currentWebsiteIssuedToUName.equals(pinnedSslIssuedToUName) ||
                 !currentWebsiteIssuedByCName.equals(pinnedSslIssuedByCName) || !currentWebsiteIssuedByOName.equals(pinnedSslIssuedByOName) ||
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.java b/app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.java
deleted file mode 100644 (file)
index 06187db..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright © 2019 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
- *
- *
- *
- * This file is a modified version of <https://android.googlesource.com/platform/packages/apps/Camera/+/master/src/com/android/camera/ui/CheckedLinearLayout.java>.
- *
- * The original licensing information is below.
- *
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.stoutner.privacybrowser.views;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.Checkable;
-import android.widget.LinearLayout;
-
-import androidx.annotation.Nullable;
-
-public class CheckedLinearLayout extends LinearLayout implements Checkable {
-    private boolean isCurrentlyChecked;
-    private static final int[] CHECKED_STATE_SET = {
-            android.R.attr.state_checked
-    };
-
-    public CheckedLinearLayout(Context context) {
-        // Run the default commands.
-        super(context);
-    }
-
-    public CheckedLinearLayout(Context context, @Nullable AttributeSet attributeSet) {
-        // Run the default commands.
-        super(context, attributeSet);
-    }
-
-    public CheckedLinearLayout(Context context, @Nullable AttributeSet attributeSet, int defaultStyleAttribute) {
-        // Run the default commands.
-        super(context, attributeSet, defaultStyleAttribute);
-    }
-
-    /*  This constructor can only be added once the minimum API >= 21.
-    public CheckedLinearLayout(Context context, @Nullable AttributeSet attributeSet, int defaultStyleAttribute, int defaultStyleResource) {
-        // Run the default commands.
-        super(context, attributeSet, defaultStyleAttribute, defaultStyleResource);
-    } */
-
-    @Override
-    public boolean isChecked() {
-        // Return the checked status.
-        return isCurrentlyChecked;
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-        // Only process the command if a change is requested.
-        if (isCurrentlyChecked != checked) {
-            // Update the is currently checked tracker.
-            isCurrentlyChecked = checked;
-
-            // Refresh the drawable state.
-            refreshDrawableState();
-
-            // Propagate the checked status to the child views.
-            for (int i = 0; i < getChildCount(); i++) {
-                // Get a handle for the child view.
-                View childView = getChildAt(i);
-
-                // Propagate the checked status if the child view is checkable.
-                if (childView instanceof Checkable) {
-                    // Cast the child view to `Checkable`.
-                    Checkable checkableChildView = (Checkable) childView;
-
-                    // Set the checked status.
-                    checkableChildView.setChecked(checked);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void toggle() {
-        // Toggle the state.
-        setChecked(!isCurrentlyChecked);
-    }
-
-    @Override
-    public int[] onCreateDrawableState(int extraSpace) {
-        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
-
-        if (isCurrentlyChecked) {
-            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
-        }
-
-        return drawableState;
-    }
-}
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.kt b/app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.kt
new file mode 100644 (file)
index 0000000..bf467d2
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2019,2021 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * This file is a modified version of <https://android.googlesource.com/platform/packages/apps/Camera/+/master/src/com/android/camera/ui/CheckedLinearLayout.java>.
+ *
+ * The original licensing information is below.
+ *
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.stoutner.privacybrowser.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.Checkable
+import android.widget.LinearLayout
+
+// Define the class constants.
+
+class CheckedLinearLayout : LinearLayout, Checkable {
+    // Define the class variables.
+    private var isCurrentlyChecked = false
+    private val checkedStateSet = intArrayOf(android.R.attr.state_checked)
+
+    // The constructors.
+    constructor(context: Context) : super(context)
+
+    constructor(context: Context, attributeSet: AttributeSet?) : super(context, attributeSet)
+
+    constructor(context: Context, attributeSet: AttributeSet?, defaultStyleAttribute: Int) : super(context, attributeSet, defaultStyleAttribute)
+
+    // This constructor can only be added once the minimum API >= 21.
+    // constructor(context: Context, attributeSet: AttributeSet?, defaultStyleAttribute: Int, defaultStyleResource: Int) : super(context, attributeSet, defaultStyleAttribute, defaultStyleResource)
+
+    override fun isChecked(): Boolean {
+        // Return the checked status.
+        return isCurrentlyChecked
+    }
+
+    override fun setChecked(checked: Boolean) {
+        // Only process the command if a change is requested.
+        if (isCurrentlyChecked != checked) {
+            // Update the status tracker.
+            isCurrentlyChecked = checked
+
+            // Refresh the drawable state.
+            refreshDrawableState()
+
+            // Propagate the checked status to the child views.
+            for (i in 0 until childCount) {
+                // Get a handle for the child view.
+                val childView = getChildAt(i)
+
+                // Propagate the checked status if the child view is checkable.
+                if (childView is Checkable) {
+                    // Cast the child view to `Checkable`.
+                    val checkableChildView = childView as Checkable
+
+                    // Set the checked status.
+                    checkableChildView.isChecked = checked
+                }
+            }
+        }
+    }
+
+    override fun toggle() {
+        // Toggle the state.
+        isChecked = !isCurrentlyChecked
+    }
+
+    public override fun onCreateDrawableState(extraSpace: Int): IntArray {
+        // Run the default commands.
+        val drawableState = super.onCreateDrawableState(extraSpace + 1)
+
+        if (isCurrentlyChecked) {
+            // Merge the drawable states.
+            mergeDrawableStates(drawableState, checkedStateSet)
+        }
+
+        // Return the drawable state.
+        return drawableState
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java
deleted file mode 100644 (file)
index 5d6dc86..0000000
+++ /dev/null
@@ -1,975 +0,0 @@
-/*
- * Copyright © 2019-2021 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.views;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.webkit.HttpAuthHandler;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebView;
-
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.NestedScrollingChild2;
-import androidx.core.view.NestedScrollingChildHelper;
-import androidx.core.view.ViewCompat;
-
-import com.stoutner.privacybrowser.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-// NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen).
-public class NestedScrollWebView extends WebView implements NestedScrollingChild2 {
-    // Define the blocklists constants.
-    public final static int BLOCKED_REQUESTS = 0;
-    public final static int EASYLIST = 1;
-    public final static int EASYPRIVACY = 2;
-    public final static int FANBOYS_ANNOYANCE_LIST = 3;
-    public final static int FANBOYS_SOCIAL_BLOCKING_LIST = 4;
-    public final static int ULTRALIST = 5;
-    public final static int ULTRAPRIVACY = 6;
-    public final static int THIRD_PARTY_REQUESTS = 7;
-
-    // Define the saved state constants.
-    private final String DOMAIN_SETTINGS_APPLIED = "domain_settings_applied";
-    private final String DOMAIN_SETTINGS_DATABASE_ID = "domain_settings_database_id";
-    private final String CURRENT_URl = "current_url";
-    private final String CURRENT_DOMAIN_NAME = "current_domain_name";
-    private final String ACCEPT_COOKIES = "accept_cookies";
-    private final String EASYLIST_ENABLED = "easylist_enabled";
-    private final String EASYPRIVACY_ENABLED = "easyprivacy_enabled";
-    private final String FANBOYS_ANNOYANCE_LIST_ENABLED = "fanboys_annoyance_list_enabled";
-    private final String FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED = "fanboys_social_blocking_list_enabled";
-    private final String ULTRALIST_ENABLED = "ultralist_enabled";
-    private final String ULTRAPRIVACY_ENABLED = "ultraprivacy_enabled";
-    private final String BLOCK_ALL_THIRD_PARTY_REQUESTS = "block_all_third_party_requests";
-    private final String HAS_PINNED_SSL_CERTIFICATE = "has_pinned_ssl_certificate";
-    private final String PINNED_SSL_ISSUED_TO_CNAME = "pinned_ssl_issued_to_cname";
-    private final String PINNED_SSL_ISSUED_TO_ONAME = "pinned_ssl_issued_to_oname";
-    private final String PINNED_SSL_ISSUED_TO_UNAME = "pinned_ssl_issued_to_uname";
-    private final String PINNED_SSL_ISSUED_BY_CNAME = "pinned_ssl_issued_by_cname";
-    private final String PINNED_SSL_ISSUED_BY_ONAME = "pinned_ssl_issued_by_oname";
-    private final String PINNED_SSL_ISSUED_BY_UNAME = "pinned_ssl_issued_by_uname";
-    private final String PINNED_SSL_START_DATE = "pinned_ssl_start_date";
-    private final String PINNED_SSL_END_DATE = "pinned_ssl_end_date";
-    private final String HAS_PINNED_IP_ADDRESSES = "has_pinned_ip_addresses";
-    private final String PINNED_IP_ADDRESSES = "pinned_ip_addresses";
-    private final String IGNORE_PINNED_DOMAIN_INFORMATION = "ignore_pinned_domain_information";
-    private final String SWIPE_TO_REFRESH = "swipe_to_refresh";
-    private final String JAVASCRIPT_ENABLED = "javascript_enabled";
-    private final String DOM_STORAGE_ENABLED = "dom_storage_enabled";
-    private final String USER_AGENT = "user_agent";
-    private final String WIDE_VIEWPORT = "wide_viewport";
-    private final String FONT_SIZE = "font_size";
-
-    // Keep a copy of the WebView fragment ID.
-    private long webViewFragmentId;
-
-    // Store the handlers.
-    private SslErrorHandler sslErrorHandler;
-    private HttpAuthHandler httpAuthHandler;
-
-    // Track if domain settings are applied to this nested scroll WebView and, if so, the database ID.
-    private boolean domainSettingsApplied;
-    private int domainSettingsDatabaseId;
-
-    // Keep track of the current URL.  This is used to not block resource requests to the main URL.
-    private String currentUrl;
-
-    // Keep track of when the domain name changes so that domain settings can be reapplied.  This should never be null.
-    private String currentDomainName = "";
-
-    // Track the cookie status, which is necessary because cookie status is app wide instead of WebView specific.
-    private boolean acceptCookies;
-
-    // Track the resource requests.
-    private final List<String[]> resourceRequests = Collections.synchronizedList(new ArrayList<>());  // Using a synchronized list makes adding resource requests thread safe.
-    private boolean easyListEnabled;
-    private boolean easyPrivacyEnabled;
-    private boolean fanboysAnnoyanceListEnabled;
-    private boolean fanboysSocialBlockingListEnabled;
-    private boolean ultraListEnabled;
-    private boolean ultraPrivacyEnabled;
-    private boolean blockAllThirdPartyRequests;
-    private int blockedRequests;
-    private int easyListBlockedRequests;
-    private int easyPrivacyBlockedRequests;
-    private int fanboysAnnoyanceListBlockedRequests;
-    private int fanboysSocialBlockingListBlockedRequests;
-    private int ultraListBlockedRequests;
-    private int ultraPrivacyBlockedRequests;
-    private int thirdPartyBlockedRequests;
-
-    // The pinned SSL certificate variables.
-    private boolean hasPinnedSslCertificate;
-    private String pinnedSslIssuedToCName;
-    private String pinnedSslIssuedToOName;
-    private String pinnedSslIssuedToUName;
-    private String pinnedSslIssuedByCName;
-    private String pinnedSslIssuedByOName;
-    private String pinnedSslIssuedByUName;
-    private Date pinnedSslStartDate;
-    private Date pinnedSslEndDate;
-
-    // The current IP addresses variables.
-    private boolean hasCurrentIpAddresses;
-    private String currentIpAddresses;
-
-    // The pinned IP addresses variables.
-    private boolean hasPinnedIpAddresses;
-    private String pinnedIpAddresses;
-
-    // The ignore pinned domain information tracker.  This is set when a user proceeds past a pinned mismatch dialog to prevent the dialog from showing again until after the domain changes.
-    private boolean ignorePinnedDomainInformation;
-
-    // The default or favorite icon.
-    private Bitmap favoriteOrDefaultIcon;
-
-    // Track swipe to refresh.
-    private boolean swipeToRefresh;
-
-    // Track a URL waiting for a proxy.
-    private String waitingForProxyUrlString = "";
-
-    // The nested scrolling child helper is used throughout the class.
-    private final NestedScrollingChildHelper nestedScrollingChildHelper;
-
-    // The previous Y position needs to be tracked between motion events.
-    private int previousYPosition;
-
-
-
-    // The basic constructor.
-    public NestedScrollWebView(Context context) {
-        // Roll up to the next constructor.
-        this(context, null);
-    }
-
-    // The intermediate constructor.
-    public NestedScrollWebView(Context context, AttributeSet attributeSet) {
-        // Roll up to the next constructor.
-        this(context, attributeSet, android.R.attr.webViewStyle);
-    }
-
-    // The full constructor.
-    public NestedScrollWebView(Context context, AttributeSet attributeSet, int defaultStyle) {
-        // Run the default commands.
-        super(context, attributeSet, defaultStyle);
-
-        // Initialize the nested scrolling child helper.
-        nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
-
-        // Enable nested scrolling by default.
-        nestedScrollingChildHelper.setNestedScrollingEnabled(true);
-    }
-
-
-
-    // WebView Fragment ID.
-    public void setWebViewFragmentId(long webViewFragmentId) {
-        // Store the WebView fragment ID.
-        this.webViewFragmentId = webViewFragmentId;
-    }
-
-    public long getWebViewFragmentId() {
-        // Return the WebView fragment ID.
-        return webViewFragmentId;
-    }
-
-
-    // SSL error handler.
-    public void setSslErrorHandler(SslErrorHandler sslErrorHandler) {
-        // Store the current SSL error handler.
-        this.sslErrorHandler = sslErrorHandler;
-    }
-
-    public SslErrorHandler getSslErrorHandler() {
-        // Return the current SSL error handler.
-        return sslErrorHandler;
-    }
-
-    public void resetSslErrorHandler() {
-        // Reset the current SSL error handler.
-        sslErrorHandler = null;
-    }
-
-
-    // HTTP authentication handler.
-    public void setHttpAuthHandler(HttpAuthHandler httpAuthHandler) {
-        // Store the current HTTP authentication handler.
-        this.httpAuthHandler = httpAuthHandler;
-    }
-
-    public HttpAuthHandler getHttpAuthHandler() {
-        // Return the current HTTP authentication handler.
-        return httpAuthHandler;
-    }
-
-    public void resetHttpAuthHandler() {
-        // Reset the current HTTP authentication handler.
-        httpAuthHandler = null;
-    }
-
-
-    // Domain settings.
-    public void setDomainSettingsApplied(boolean applied) {
-        // Store the domain settings applied status.
-        domainSettingsApplied = applied;
-    }
-
-    public boolean getDomainSettingsApplied() {
-        // Return the domain settings applied status.
-        return domainSettingsApplied;
-    }
-
-
-    // Domain settings database ID.
-    public void setDomainSettingsDatabaseId(int databaseId) {
-        // Store the domain settings database ID.
-        domainSettingsDatabaseId = databaseId;
-    }
-
-    public int getDomainSettingsDatabaseId() {
-        // Return the domain settings database ID.
-        return domainSettingsDatabaseId;
-    }
-
-
-    // Current URL.
-    public void setCurrentUrl(String url) {
-        // Store the current URL.
-        currentUrl = url;
-    }
-
-    public String getCurrentUrl() {
-        // Return the current URL.
-        return currentUrl;
-    }
-
-
-    // Current domain name.  To function well when called, the domain name should never be allowed to be null.
-    public void setCurrentDomainName(@NonNull String domainName) {
-        // Store the current domain name.
-        currentDomainName = domainName;
-    }
-
-    public void resetCurrentDomainName() {
-        // Reset the current domain name.
-        currentDomainName = "";
-    }
-
-    public String getCurrentDomainName() {
-        // Return the current domain name.
-        return currentDomainName;
-    }
-
-
-    // Cookies.
-    public void setAcceptCookies(boolean status) {
-        // Store the accept cookies status.
-        acceptCookies = status;
-    }
-
-    public boolean getAcceptCookies() {
-        // Return the accept cookies status.
-        return acceptCookies;
-    }
-
-
-    // Resource requests.
-    public void addResourceRequest(String[] resourceRequest) {
-        // Add the resource request to the list.
-        resourceRequests.add(resourceRequest);
-    }
-
-    public List<String[]> getResourceRequests() {
-        // Return the list of resource requests as an array list.
-        return resourceRequests;
-    }
-
-    public void clearResourceRequests() {
-        // Clear the resource requests.
-        resourceRequests.clear();
-    }
-
-
-    // Blocklists.
-    public void enableBlocklist(int blocklist, boolean status) {
-        // Update the status of the indicated blocklist.
-        switch (blocklist) {
-            case EASYLIST:
-                // Update the status of the blocklist.
-                easyListEnabled = status;
-                break;
-
-            case EASYPRIVACY:
-                // Update the status of the blocklist.
-                easyPrivacyEnabled = status;
-                break;
-
-            case FANBOYS_ANNOYANCE_LIST:
-                // Update the status of the blocklist.
-                fanboysAnnoyanceListEnabled = status;
-                break;
-
-            case FANBOYS_SOCIAL_BLOCKING_LIST:
-                // Update the status of the blocklist.
-                fanboysSocialBlockingListEnabled = status;
-                break;
-
-            case ULTRALIST:
-                // Update the status of the blocklist.
-                ultraListEnabled = status;
-                break;
-
-            case ULTRAPRIVACY:
-                // Update the status of the blocklist.
-                ultraPrivacyEnabled = status;
-                break;
-
-            case THIRD_PARTY_REQUESTS:
-                // Update the status of the blocklist.
-                blockAllThirdPartyRequests = status;
-                break;
-        }
-    }
-
-    public boolean isBlocklistEnabled(int blocklist) {
-        // Get the status of the indicated blocklist.
-        switch (blocklist) {
-            case EASYLIST:
-                // Return the status of the blocklist.
-                return easyListEnabled;
-
-            case EASYPRIVACY:
-                // Return the status of the blocklist.
-                return easyPrivacyEnabled;
-
-            case FANBOYS_ANNOYANCE_LIST:
-                // Return the status of the blocklist.
-                return fanboysAnnoyanceListEnabled;
-
-            case FANBOYS_SOCIAL_BLOCKING_LIST:
-                // Return the status of the blocklist.
-                return fanboysSocialBlockingListEnabled;
-
-            case ULTRALIST:
-                // Return the status of the blocklist.
-                return ultraListEnabled;
-
-            case ULTRAPRIVACY:
-                // Return the status of the blocklist.
-                return ultraPrivacyEnabled;
-
-            case THIRD_PARTY_REQUESTS:
-                // Return the status of the blocklist.
-                return blockAllThirdPartyRequests;
-
-            default:
-                // The default value is required but should never be used.
-                return false;
-        }
-    }
-
-
-    // Resource request counters.
-    public void resetRequestsCounters() {
-        // Reset all the resource request counters.
-        blockedRequests = 0;
-        easyListBlockedRequests = 0;
-        easyPrivacyBlockedRequests = 0;
-        fanboysAnnoyanceListBlockedRequests = 0;
-        fanboysSocialBlockingListBlockedRequests = 0;
-        ultraListBlockedRequests = 0;
-        ultraPrivacyBlockedRequests = 0;
-        thirdPartyBlockedRequests = 0;
-    }
-
-    public void incrementRequestsCount(int blocklist) {
-        // Increment the count of the indicated blocklist.
-        switch (blocklist) {
-            case BLOCKED_REQUESTS:
-                // Increment the blocked requests count.
-                blockedRequests++;
-                break;
-
-            case EASYLIST:
-                // Increment the EasyList blocked requests count.
-                easyListBlockedRequests++;
-                break;
-
-            case EASYPRIVACY:
-                // Increment the EasyPrivacy blocked requests count.
-                easyPrivacyBlockedRequests++;
-                break;
-
-            case FANBOYS_ANNOYANCE_LIST:
-                // Increment the Fanboy's Annoyance List blocked requests count.
-                fanboysAnnoyanceListBlockedRequests++;
-                break;
-
-            case FANBOYS_SOCIAL_BLOCKING_LIST:
-                // Increment the Fanboy's Social Blocking List blocked requests count.
-                fanboysSocialBlockingListBlockedRequests++;
-                break;
-
-            case ULTRALIST:
-                // Increment the UltraList blocked requests count.
-                ultraListBlockedRequests++;
-                break;
-
-            case ULTRAPRIVACY:
-                // Increment the UltraPrivacy blocked requests count.
-                ultraPrivacyBlockedRequests++;
-                break;
-
-            case THIRD_PARTY_REQUESTS:
-                // Increment the Third Party blocked requests count.
-                thirdPartyBlockedRequests++;
-                break;
-        }
-    }
-
-    public int getRequestsCount(int blocklist) {
-        // Get the count of the indicated blocklist.
-        switch (blocklist) {
-            case BLOCKED_REQUESTS:
-                // Return the blocked requests count.
-                return blockedRequests;
-
-            case EASYLIST:
-                // Return the EasyList blocked requests count.
-                return easyListBlockedRequests;
-
-            case EASYPRIVACY:
-                // Return the EasyPrivacy blocked requests count.
-                return easyPrivacyBlockedRequests;
-
-            case FANBOYS_ANNOYANCE_LIST:
-                // Return the Fanboy's Annoyance List blocked requests count.
-                return fanboysAnnoyanceListBlockedRequests;
-
-            case FANBOYS_SOCIAL_BLOCKING_LIST:
-                // Return the Fanboy's Social Blocking List blocked requests count.
-                return fanboysSocialBlockingListBlockedRequests;
-
-            case ULTRALIST:
-                // Return the UltraList blocked requests count.
-                return ultraListBlockedRequests;
-
-            case ULTRAPRIVACY:
-                // Return the UltraPrivacy blocked requests count.
-                return ultraPrivacyBlockedRequests;
-
-            case THIRD_PARTY_REQUESTS:
-                // Return the Third Party blocked requests count.
-                return thirdPartyBlockedRequests;
-
-            default:
-                // Return 0.  This should never end up being called.
-                return 0;
-        }
-    }
-
-
-    // Pinned SSL certificates.
-    public boolean hasPinnedSslCertificate() {
-        // Return the status of the pinned SSL certificate.
-        return hasPinnedSslCertificate;
-    }
-
-    public void setPinnedSslCertificate(String issuedToCName, String issuedToOName, String issuedToUName, String issuedByCName, String issuedByOName, String issuedByUName, Date startDate, Date endDate) {
-        // Store the pinned SSL certificate information.
-        pinnedSslIssuedToCName = issuedToCName;
-        pinnedSslIssuedToOName = issuedToOName;
-        pinnedSslIssuedToUName = issuedToUName;
-        pinnedSslIssuedByCName = issuedByCName;
-        pinnedSslIssuedByOName = issuedByOName;
-        pinnedSslIssuedByUName = issuedByUName;
-        pinnedSslStartDate = startDate;
-        pinnedSslEndDate = endDate;
-
-        // Set the pinned SSL certificate tracker.
-        hasPinnedSslCertificate = true;
-    }
-
-    public ArrayList<Object> getPinnedSslCertificate() {
-        // Initialize an array list.
-        ArrayList<Object> arrayList = new ArrayList<>();
-
-        // Create the SSL certificate string array.
-        String[] sslCertificateStringArray = new String[] {pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName};
-
-        // Create the SSL certificate date array.
-        Date[] sslCertificateDateArray = new Date[] {pinnedSslStartDate, pinnedSslEndDate};
-
-        // Add the arrays to the array list.
-        arrayList.add(sslCertificateStringArray);
-        arrayList.add(sslCertificateDateArray);
-
-        // Return the pinned SSL certificate array list.
-        return arrayList;
-    }
-
-    public void clearPinnedSslCertificate() {
-        // Clear the pinned SSL certificate.
-        pinnedSslIssuedToCName = null;
-        pinnedSslIssuedToOName = null;
-        pinnedSslIssuedToUName = null;
-        pinnedSslIssuedByCName = null;
-        pinnedSslIssuedByOName = null;
-        pinnedSslIssuedByUName = null;
-        pinnedSslStartDate = null;
-        pinnedSslEndDate = null;
-
-        // Clear the pinned SSL certificate tracker.
-        hasPinnedSslCertificate = false;
-    }
-
-
-    // Current IP addresses.
-    public boolean hasCurrentIpAddresses() {
-        // Return the status of the current IP addresses.
-        return hasCurrentIpAddresses;
-    }
-
-    public void setCurrentIpAddresses(String ipAddresses) {
-        // Store the current IP addresses.
-        currentIpAddresses = ipAddresses;
-
-        // Set the current IP addresses tracker.
-        hasCurrentIpAddresses = true;
-    }
-
-    public String getCurrentIpAddresses() {
-        // Return the current IP addresses.
-        return currentIpAddresses;
-    }
-
-    public void clearCurrentIpAddresses() {
-        // Clear the current IP addresses.
-        currentIpAddresses = null;
-
-        // Clear the current IP addresses tracker.
-        hasCurrentIpAddresses = false;
-    }
-
-
-    // Pinned IP addresses.
-    public boolean hasPinnedIpAddresses() {
-        // Return the status of the pinned IP addresses.
-        return hasPinnedIpAddresses;
-    }
-
-    public void setPinnedIpAddresses(String ipAddresses) {
-        // Store the pinned IP addresses.
-        pinnedIpAddresses = ipAddresses;
-
-        // Set the pinned IP addresses tracker.
-        hasPinnedIpAddresses = true;
-    }
-
-    public String getPinnedIpAddresses() {
-        // Return the pinned IP addresses.
-        return pinnedIpAddresses;
-    }
-
-    public void clearPinnedIpAddresses() {
-        // Clear the pinned IP addresses.
-        pinnedIpAddresses = null;
-
-        // Clear the pinned IP addresses tracker.
-        hasPinnedIpAddresses = false;
-    }
-
-
-    // Ignore pinned information.
-    public void setIgnorePinnedDomainInformation(boolean status) {
-        // Set the status of the ignore pinned domain information tracker.
-        ignorePinnedDomainInformation = status;
-    }
-
-    public boolean ignorePinnedDomainInformation() {
-        // Return the status of the ignore pinned domain information tracker.
-        return ignorePinnedDomainInformation;
-    }
-
-
-    // Favorite or default icon.
-    public void initializeFavoriteIcon() {
-        // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
-        Drawable favoriteIconDrawable = ContextCompat.getDrawable(getContext(), R.drawable.world);
-
-        // Cast the favorite icon drawable to a bitmap drawable.
-        BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable;
-
-        // Remove the incorrect warning below that the favorite icon bitmap drawable might be null.
-        assert favoriteIconBitmapDrawable != null;
-
-        // Store the default icon bitmap.
-        favoriteOrDefaultIcon = favoriteIconBitmapDrawable.getBitmap();
-    }
-
-    public void setFavoriteOrDefaultIcon(Bitmap icon) {
-        // Scale the favorite icon bitmap down if it is larger than 256 x 256.  Filtering uses bilinear interpolation.
-        if ((icon.getHeight() > 256) || (icon.getWidth() > 256)) {
-            favoriteOrDefaultIcon = Bitmap.createScaledBitmap(icon, 256, 256, true);
-        } else {
-            // Store the icon as presented.
-            favoriteOrDefaultIcon = icon;
-        }
-    }
-
-    public Bitmap getFavoriteOrDefaultIcon() {
-        // Return the favorite or default icon.
-        return favoriteOrDefaultIcon;
-    }
-
-
-    // Swipe to refresh.
-    public void setSwipeToRefresh(boolean status) {
-        // Store the swipe to refresh status.
-        swipeToRefresh = status;
-    }
-
-    public boolean getSwipeToRefresh() {
-        // Return the swipe to refresh status.
-        return swipeToRefresh;
-    }
-
-
-    // Waiting for proxy.
-    public void setWaitingForProxyUrlString(String urlString) {
-        // Store the waiting for proxy URL string.
-        waitingForProxyUrlString = urlString;
-    }
-
-    public String getWaitingForProxyUrlString() {
-        // Return the waiting for proxy URL string.
-        return waitingForProxyUrlString;
-    }
-
-    public void resetWaitingForProxyUrlString() {
-        // Clear the waiting for proxy URL string.
-        waitingForProxyUrlString = "";
-    }
-
-    // Scroll range.
-    public int getHorizontalScrollRange() {
-        // Return the horizontal scroll range.
-        return computeHorizontalScrollRange();
-    }
-
-    public int getVerticalScrollRange() {
-        // Return the vertical scroll range.
-        return computeVerticalScrollRange();
-    }
-
-
-
-    @Override
-    public boolean onTouchEvent(MotionEvent motionEvent) {
-        // Run the commands for the given motion event action.
-        switch (motionEvent.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                // Start nested scrolling along the vertical axis.  `ViewCompat` must be used until the minimum API >= 21.
-                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
-
-                // Save the current Y position.  Action down will not be called again until a new motion starts.
-                previousYPosition = (int) motionEvent.getY();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                // Get the current Y position.
-                int currentYMotionPosition = (int) motionEvent.getY();
-
-                // Calculate the pre-scroll delta Y.
-                int preScrollDeltaY = previousYPosition - currentYMotionPosition;
-
-                // Initialize a variable to track how much of the scroll is consumed.
-                int[] consumedScroll = new int[2];
-
-                // Initialize a variable to track the offset in the window.
-                int[] offsetInWindow = new int[2];
-
-                // Get the WebView Y position.
-                int webViewYPosition = getScrollY();
-
-                // Set the scroll delta Y to initially be the same as the pre-scroll delta Y.
-                int scrollDeltaY = preScrollDeltaY;
-
-                // Dispatch the nested pre-school.  This scrolls the app bar if it needs it.  `offsetInWindow` will be returned with an updated value.
-                if (dispatchNestedPreScroll(0, preScrollDeltaY, consumedScroll, offsetInWindow)) {
-                    // Update the scroll delta Y if some of it was consumed.
-                    // There is currently a bug in Android where if scrolling up at a certain slow speed the input can lock the pre scroll and continue to consume it after the app bar is fully displayed.
-                    scrollDeltaY = preScrollDeltaY - consumedScroll[1];
-                }
-
-                // Check to see if the WebView is at the top and and the scroll action is downward.
-                if ((webViewYPosition == 0) && (scrollDeltaY < 0)) {  // Swipe to refresh is being engaged.
-                    // Stop the nested scroll so that swipe to refresh has complete control.  This way releasing the scroll to refresh circle doesn't scroll the WebView at the same time.
-                    stopNestedScroll();
-                } else {  // Swipe to refresh is not being engaged.
-                    // Start the nested scroll so that the app bar can scroll off the screen.
-                    startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
-
-                    // Dispatch the nested scroll.  This scrolls the WebView.  The delta Y unconsumed normally controls the swipe refresh layout, but that is handled with the `if` statement above.
-                    dispatchNestedScroll(0, scrollDeltaY, 0, 0, offsetInWindow);
-
-                    // Store the current Y position for use in the next action move.
-                    previousYPosition = previousYPosition - scrollDeltaY;
-                }
-                break;
-
-
-            default:
-                // Stop nested scrolling.
-                stopNestedScroll();
-        }
-
-        // Perform a click.  This is required by the Android accessibility guidelines.
-        performClick();
-
-        // Run the default commands and return the result.
-        return super.onTouchEvent(motionEvent);
-    }
-
-    public Bundle saveNestedScrollWebViewState() {
-        // Create a saved state bundle.
-        Bundle savedState = new Bundle();
-
-        // Initialize the long date variables.
-        long pinnedSslStartDateLong = 0;
-        long pinnedSslEndDateLong = 0;
-
-        // Convert the dates to longs.
-        if (pinnedSslStartDate != null) {
-            pinnedSslStartDateLong = pinnedSslStartDate.getTime();
-        }
-
-        if (pinnedSslEndDate != null) {
-            pinnedSslEndDateLong = pinnedSslEndDate.getTime();
-        }
-
-        // Populate the saved state bundle.
-        savedState.putBoolean(DOMAIN_SETTINGS_APPLIED, domainSettingsApplied);
-        savedState.putInt(DOMAIN_SETTINGS_DATABASE_ID, domainSettingsDatabaseId);
-        savedState.putString(CURRENT_URl, currentUrl);
-        savedState.putString(CURRENT_DOMAIN_NAME, currentDomainName);
-        savedState.putBoolean(ACCEPT_COOKIES, acceptCookies);
-        savedState.putBoolean(EASYLIST_ENABLED, easyListEnabled);
-        savedState.putBoolean(EASYPRIVACY_ENABLED, easyPrivacyEnabled);
-        savedState.putBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED, fanboysAnnoyanceListEnabled);
-        savedState.putBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED, fanboysSocialBlockingListEnabled);
-        savedState.putBoolean(ULTRALIST_ENABLED, ultraListEnabled);
-        savedState.putBoolean(ULTRAPRIVACY_ENABLED, ultraPrivacyEnabled);
-        savedState.putBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests);
-        savedState.putBoolean(HAS_PINNED_SSL_CERTIFICATE, hasPinnedSslCertificate);
-        savedState.putString(PINNED_SSL_ISSUED_TO_CNAME, pinnedSslIssuedToCName);
-        savedState.putString(PINNED_SSL_ISSUED_TO_ONAME, pinnedSslIssuedToOName);
-        savedState.putString(PINNED_SSL_ISSUED_TO_UNAME, pinnedSslIssuedToUName);
-        savedState.putString(PINNED_SSL_ISSUED_BY_CNAME, pinnedSslIssuedByCName);
-        savedState.putString(PINNED_SSL_ISSUED_BY_ONAME, pinnedSslIssuedByOName);
-        savedState.putString(PINNED_SSL_ISSUED_BY_UNAME, pinnedSslIssuedByUName);
-        savedState.putLong(PINNED_SSL_START_DATE, pinnedSslStartDateLong);
-        savedState.putLong(PINNED_SSL_END_DATE, pinnedSslEndDateLong);
-        savedState.putBoolean(HAS_PINNED_IP_ADDRESSES, hasPinnedIpAddresses);
-        savedState.putString(PINNED_IP_ADDRESSES, pinnedIpAddresses);
-        savedState.putBoolean(IGNORE_PINNED_DOMAIN_INFORMATION, ignorePinnedDomainInformation);
-        savedState.putBoolean(SWIPE_TO_REFRESH, swipeToRefresh);
-        savedState.putBoolean(JAVASCRIPT_ENABLED, this.getSettings().getJavaScriptEnabled());
-        savedState.putBoolean(DOM_STORAGE_ENABLED, this.getSettings().getDomStorageEnabled());
-        savedState.putString(USER_AGENT, this.getSettings().getUserAgentString());
-        savedState.putBoolean(WIDE_VIEWPORT, this.getSettings().getUseWideViewPort());
-        savedState.putInt(FONT_SIZE, this.getSettings().getTextZoom());
-
-        // Return the saved state bundle.
-        return savedState;
-    }
-
-    public void restoreNestedScrollWebViewState(Bundle savedState) {
-        // Restore the class variables.
-        domainSettingsApplied = savedState.getBoolean(DOMAIN_SETTINGS_APPLIED);
-        domainSettingsDatabaseId = savedState.getInt(DOMAIN_SETTINGS_DATABASE_ID);
-        currentUrl = savedState.getString(CURRENT_URl);
-        currentDomainName = savedState.getString(CURRENT_DOMAIN_NAME);
-        acceptCookies = savedState.getBoolean(ACCEPT_COOKIES);
-        easyListEnabled = savedState.getBoolean(EASYLIST_ENABLED);
-        easyPrivacyEnabled = savedState.getBoolean(EASYPRIVACY_ENABLED);
-        fanboysAnnoyanceListEnabled = savedState.getBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED);
-        fanboysSocialBlockingListEnabled = savedState.getBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED);
-        ultraListEnabled = savedState.getBoolean(ULTRALIST_ENABLED);
-        ultraPrivacyEnabled = savedState.getBoolean(ULTRAPRIVACY_ENABLED);
-        blockAllThirdPartyRequests = savedState.getBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS);
-        hasPinnedSslCertificate = savedState.getBoolean(HAS_PINNED_SSL_CERTIFICATE);
-        pinnedSslIssuedToCName = savedState.getString(PINNED_SSL_ISSUED_TO_CNAME);
-        pinnedSslIssuedToOName = savedState.getString(PINNED_SSL_ISSUED_TO_ONAME);
-        pinnedSslIssuedToUName = savedState.getString(PINNED_SSL_ISSUED_TO_UNAME);
-        pinnedSslIssuedByCName = savedState.getString(PINNED_SSL_ISSUED_BY_CNAME);
-        pinnedSslIssuedByOName = savedState.getString(PINNED_SSL_ISSUED_BY_ONAME);
-        pinnedSslIssuedByUName = savedState.getString(PINNED_SSL_ISSUED_BY_UNAME);
-        hasPinnedIpAddresses = savedState.getBoolean(HAS_PINNED_IP_ADDRESSES);
-        pinnedIpAddresses = savedState.getString(PINNED_IP_ADDRESSES);
-        ignorePinnedDomainInformation = savedState.getBoolean(IGNORE_PINNED_DOMAIN_INFORMATION);
-        swipeToRefresh = savedState.getBoolean(SWIPE_TO_REFRESH);
-        this.getSettings().setJavaScriptEnabled(savedState.getBoolean(JAVASCRIPT_ENABLED));
-        this.getSettings().setDomStorageEnabled(savedState.getBoolean(DOM_STORAGE_ENABLED));
-        this.getSettings().setUserAgentString(savedState.getString(USER_AGENT));
-        this.getSettings().setUseWideViewPort(savedState.getBoolean(WIDE_VIEWPORT));
-        this.getSettings().setTextZoom(savedState.getInt(FONT_SIZE));
-
-        // Get the date longs.
-        long pinnedSslStartDateLong = savedState.getLong(PINNED_SSL_START_DATE);
-        long pinnedSslEndDateLong = savedState.getLong(PINNED_SSL_END_DATE);
-
-        // Set the pinned SSL start date to `null` if the saved date long is 0 because creating a new date results in an error if the input is 0.
-        if (pinnedSslStartDateLong == 0) {
-            pinnedSslStartDate = null;
-        } else {
-            pinnedSslStartDate = new Date(pinnedSslStartDateLong);
-        }
-
-        // Set the Pinned SSL end date to `null` if the saved date long is 0 because creating a new date results in an error if the input is 0.
-        if (pinnedSslEndDateLong == 0) {
-            pinnedSslEndDate = null;
-        } else {
-            pinnedSslEndDate = new Date(pinnedSslEndDateLong);
-        }
-    }
-
-    // The Android accessibility guidelines require overriding `performClick()` and calling it from `onTouchEvent()`.
-    @Override
-    public boolean performClick() {
-        return super.performClick();
-    }
-
-
-    // Method from NestedScrollingChild.
-    @Override
-    public void setNestedScrollingEnabled(boolean status) {
-        // Set the status of the nested scrolling.
-        nestedScrollingChildHelper.setNestedScrollingEnabled(status);
-    }
-
-    // Method from NestedScrollingChild.
-    @Override
-    public boolean isNestedScrollingEnabled() {
-        // Return the status of nested scrolling.
-        return nestedScrollingChildHelper.isNestedScrollingEnabled();
-    }
-
-
-    // Method from NestedScrollingChild.
-    @Override
-    public boolean startNestedScroll(int axes) {
-        // Start a nested scroll along the indicated axes.
-        return nestedScrollingChildHelper.startNestedScroll(axes);
-    }
-
-    // Method from NestedScrollingChild2.
-    @Override
-    public boolean startNestedScroll(int axes, int type) {
-        // Start a nested scroll along the indicated axes for the given type of input which caused the scroll event.
-        return nestedScrollingChildHelper.startNestedScroll(axes, type);
-    }
-
-
-    // Method from NestedScrollingChild.
-    @Override
-    public void stopNestedScroll() {
-        // Stop the nested scroll.
-        nestedScrollingChildHelper.stopNestedScroll();
-    }
-
-    // Method from NestedScrollingChild2.
-    @Override
-    public void stopNestedScroll(int type) {
-        // Stop the nested scroll of the given type of input which caused the scroll event.
-        nestedScrollingChildHelper.stopNestedScroll(type);
-    }
-
-
-    // Method from NestedScrollingChild.
-    @Override
-    public boolean hasNestedScrollingParent() {
-        // Return the status of the nested scrolling parent.
-        return nestedScrollingChildHelper.hasNestedScrollingParent();
-    }
-
-    // Method from NestedScrollingChild2.
-    @Override
-    public boolean hasNestedScrollingParent(int type) {
-        // return the status of the nested scrolling parent for the given type of input which caused the scroll event.
-        return nestedScrollingChildHelper.hasNestedScrollingParent(type);
-    }
-
-
-    // Method from NestedScrollingChild.
-    @Override
-    public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow) {
-        // Dispatch a nested pre-scroll with the specified deltas, which lets a parent to consume some of the scroll if desired.
-        return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow);
-    }
-
-    // Method from NestedScrollingChild2.
-    @Override
-    public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow, int type) {
-        // Dispatch a nested pre-scroll with the specified deltas for the given type of input which caused the scroll event, which lets a parent to consume some of the scroll if desired.
-        return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow, type);
-    }
-
-
-    // Method from NestedScrollingChild.
-    @Override
-    public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow) {
-        // Dispatch a nested scroll with the specified deltas.
-        return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow);
-    }
-
-    // Method from NestedScrollingChild2.
-    @Override
-    public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow, int type) {
-        // Dispatch a nested scroll with the specified deltas for the given type of input which caused the scroll event.
-        return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow, type);
-    }
-
-
-    // Method from NestedScrollingChild.
-    @Override
-    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
-        // Dispatch a nested pre-fling with the specified velocity, which lets a parent consume the fling if desired.
-        return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
-    }
-
-    // Method from NestedScrollingChild.
-    @Override
-    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
-        // Dispatch a nested fling with the specified velocity.
-        return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt
new file mode 100644 (file)
index 0000000..2900e0a
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Copyright © 2019-2021 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.views
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.os.Bundle
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.webkit.WebView
+import android.webkit.SslErrorHandler
+import android.webkit.HttpAuthHandler
+
+import androidx.core.content.ContextCompat
+import androidx.core.view.NestedScrollingChild2
+import androidx.core.view.NestedScrollingChildHelper
+import androidx.core.view.ViewCompat
+
+import com.stoutner.privacybrowser.R
+
+import java.util.Collections
+import java.util.Date
+
+import kotlin.collections.ArrayList
+
+import kotlin.jvm.JvmOverloads
+
+// Define the saved state constants.
+private const val DOMAIN_SETTINGS_APPLIED = "domain_settings_applied"
+private const val DOMAIN_SETTINGS_DATABASE_ID = "domain_settings_database_id"
+private const val CURRENT_DOMAIN_NAME = "current_domain_name"
+private const val CURRENT_URl = "current_url"
+private const val ACCEPT_COOKIES = "accept_cookies"
+private const val EASYLIST_ENABLED = "easylist_enabled"
+private const val EASYPRIVACY_ENABLED = "easyprivacy_enabled"
+private const val FANBOYS_ANNOYANCE_LIST_ENABLED = "fanboys_annoyance_list_enabled"
+private const val FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED = "fanboys_social_blocking_list_enabled"
+private const val ULTRALIST_ENABLED = "ultralist_enabled"
+private const val ULTRAPRIVACY_ENABLED = "ultraprivacy_enabled"
+private const val BLOCK_ALL_THIRD_PARTY_REQUESTS = "block_all_third_party_requests"
+private const val HAS_PINNED_SSL_CERTIFICATE = "has_pinned_ssl_certificate"
+private const val PINNED_SSL_ISSUED_TO_CNAME = "pinned_ssl_issued_to_cname"
+private const val PINNED_SSL_ISSUED_TO_ONAME = "pinned_ssl_issued_to_oname"
+private const val PINNED_SSL_ISSUED_TO_UNAME = "pinned_ssl_issued_to_uname"
+private const val PINNED_SSL_ISSUED_BY_CNAME = "pinned_ssl_issued_by_cname"
+private const val PINNED_SSL_ISSUED_BY_ONAME = "pinned_ssl_issued_by_oname"
+private const val PINNED_SSL_ISSUED_BY_UNAME = "pinned_ssl_issued_by_uname"
+private const val PINNED_SSL_START_DATE = "pinned_ssl_start_date"
+private const val PINNED_SSL_END_DATE = "pinned_ssl_end_date"
+private const val PINNED_IP_ADDRESSES = "pinned_ip_addresses"
+private const val IGNORE_PINNED_DOMAIN_INFORMATION = "ignore_pinned_domain_information"
+private const val SWIPE_TO_REFRESH = "swipe_to_refresh"
+private const val JAVASCRIPT_ENABLED = "javascript_enabled"
+private const val DOM_STORAGE_ENABLED = "dom_storage_enabled"
+private const val USER_AGENT = "user_agent"
+private const val WIDE_VIEWPORT = "wide_viewport"
+private const val FONT_SIZE = "font_size"
+
+// NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen).  It also stores extra information about the state of the WebView used by Privacy Browser.
+class NestedScrollWebView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, defaultStyle: Int = android.R.attr.webViewStyle) : WebView(context, attributeSet, defaultStyle),
+    NestedScrollingChild2 {
+
+    companion object {
+        // Define the companion object blocklists constants.  These can be moved to class constants once all of the code has transitioned to Kotlin.
+        const val BLOCKED_REQUESTS = 0
+        const val EASYLIST = 1
+        const val EASYPRIVACY = 2
+        const val FANBOYS_ANNOYANCE_LIST = 3
+        const val FANBOYS_SOCIAL_BLOCKING_LIST = 4
+        const val ULTRALIST = 5
+        const val ULTRAPRIVACY = 6
+        const val THIRD_PARTY_REQUESTS = 7
+    }
+
+    // Define the public variables.
+    var acceptCookies = false
+    var blockAllThirdPartyRequests = false
+    var currentDomainName = ""
+    var currentIpAddresses = ""
+    var currentUrl = ""
+    var domainSettingsApplied = false
+    var domainSettingsDatabaseId = 0
+    var easyListEnabled = true
+    var easyPrivacyEnabled = true
+    var fanboysAnnoyanceListEnabled = true
+    var fanboysSocialBlockingListEnabled = true
+    var httpAuthHandler: HttpAuthHandler? = null
+    var ignorePinnedDomainInformation = false
+    var pinnedIpAddresses = ""
+    var sslErrorHandler: SslErrorHandler? = null
+    var swipeToRefresh = false
+    var ultraListEnabled = true
+    var ultraPrivacyEnabled = true
+    var waitingForProxyUrlString = ""
+    var webViewFragmentId: Long = 0
+
+
+    // Define the private variables.
+    private val nestedScrollingChildHelper: NestedScrollingChildHelper = NestedScrollingChildHelper(this)
+    private lateinit var favoriteOrDefaultIcon: Bitmap
+    private var previousYPosition = 0  // The previous Y position needs to be tracked between motion events.
+    private var hasPinnedSslCertificate = false
+    private var pinnedSslIssuedToCName = ""
+    private var pinnedSslIssuedToOName = ""
+    private var pinnedSslIssuedToUName = ""
+    private var pinnedSslIssuedByCName = ""
+    private var pinnedSslIssuedByOName = ""
+    private var pinnedSslIssuedByUName = ""
+    private var pinnedSslStartDate = Date(0)
+    private var pinnedSslEndDate = Date(0)
+    private val resourceRequests = Collections.synchronizedList(ArrayList<Array<String>>())  // Using a synchronized list makes adding resource requests thread safe.
+    private var blockedRequests = 0
+    private var easyListBlockedRequests = 0
+    private var easyPrivacyBlockedRequests = 0
+    private var fanboysAnnoyanceListBlockedRequests = 0
+    private var fanboysSocialBlockingListBlockedRequests = 0
+    private var ultraListBlockedRequests = 0
+    private var ultraPrivacyBlockedRequests = 0
+    private var thirdPartyBlockedRequests = 0
+
+    init {
+        // Enable nested scrolling by default.
+        nestedScrollingChildHelper.isNestedScrollingEnabled = true
+
+        // Initialize the favorite icon.
+        initializeFavoriteIcon()
+    }
+
+
+    // Favorite or default icon.
+    fun initializeFavoriteIcon() {
+        // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
+        val favoriteIconDrawable = ContextCompat.getDrawable(context, R.drawable.world)
+
+        // Cast the favorite icon drawable to a bitmap drawable.
+        val favoriteIconBitmapDrawable = (favoriteIconDrawable as BitmapDrawable?)!!
+
+        // Store the default icon bitmap.
+        favoriteOrDefaultIcon = favoriteIconBitmapDrawable.bitmap
+    }
+
+    fun setFavoriteOrDefaultIcon(icon: Bitmap) {
+        // Scale the favorite icon bitmap down if it is larger than 256 x 256.  Filtering uses bilinear interpolation.
+        favoriteOrDefaultIcon = if (icon.height > 256 || icon.width > 256) {
+            Bitmap.createScaledBitmap(icon, 256, 256, true)
+        } else {
+            // Store the icon as presented.
+            icon
+        }
+    }
+
+    fun getFavoriteOrDefaultIcon(): Bitmap {
+        // Return the favorite or default icon.  This is the only way to return a non-nullable variable while retaining the custom initialization and setter functions above.
+        return favoriteOrDefaultIcon
+    }
+
+
+    // Reset the handlers.
+    fun resetSslErrorHandler() {
+        // Reset the current SSL error handler.
+        sslErrorHandler = null
+    }
+
+    fun resetHttpAuthHandler() {
+        // Reset the current HTTP authentication handler.
+        httpAuthHandler = null
+    }
+
+
+    // Pinned SSL certificates.
+    fun hasPinnedSslCertificate(): Boolean {
+        // Return the status of the pinned SSL certificate.
+        return hasPinnedSslCertificate
+    }
+
+    fun setPinnedSslCertificate(issuedToCName: String, issuedToOName: String, issuedToUName: String, issuedByCName: String, issuedByOName: String, issuedByUName: String, startDate: Date, endDate: Date) {
+        // Store the pinned SSL certificate information.
+        pinnedSslIssuedToCName = issuedToCName
+        pinnedSslIssuedToOName = issuedToOName
+        pinnedSslIssuedToUName = issuedToUName
+        pinnedSslIssuedByCName = issuedByCName
+        pinnedSslIssuedByOName = issuedByOName
+        pinnedSslIssuedByUName = issuedByUName
+        pinnedSslStartDate = startDate
+        pinnedSslEndDate = endDate
+
+        // Set the pinned SSL certificate tracker.
+        hasPinnedSslCertificate = true
+    }
+
+    fun getPinnedSslCertificate(): ArrayList<Any> {
+        // Initialize an array list.
+        val arrayList = ArrayList<Any>()
+
+        // Create the SSL certificate string array.
+        val sslCertificateStringArray = arrayOf(pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName)
+
+        // Create the SSL certificate date array.
+        val sslCertificateDateArray = arrayOf(pinnedSslStartDate, pinnedSslEndDate)
+
+        // Add the arrays to the array list.
+        arrayList.add(sslCertificateStringArray)
+        arrayList.add(sslCertificateDateArray)
+
+        // Return the pinned SSL certificate array list.
+        return arrayList
+    }
+
+    fun clearPinnedSslCertificate() {
+        // Clear the pinned SSL certificate.
+        pinnedSslIssuedToCName = ""
+        pinnedSslIssuedToOName = ""
+        pinnedSslIssuedToUName = ""
+        pinnedSslIssuedByCName = ""
+        pinnedSslIssuedByOName = ""
+        pinnedSslIssuedByUName = ""
+        pinnedSslStartDate = Date(0)
+        pinnedSslEndDate = Date(0)
+
+        // Clear the pinned SSL certificate tracker.
+        hasPinnedSslCertificate = false
+    }
+
+
+    // Resource requests.
+    fun addResourceRequest(resourceRequest: Array<String>) {
+        // Add the resource request to the list.
+        resourceRequests.add(resourceRequest)
+    }
+
+    fun getResourceRequests(): List<Array<String>> {
+        // Return the list of resource requests as an array list.
+        return resourceRequests
+    }
+
+    fun clearResourceRequests() {
+        // Clear the resource requests.
+        resourceRequests.clear()
+    }
+
+
+    // Resource request counters.
+    fun incrementRequestsCount(blocklist: Int) {
+        // Increment the count of the indicated blocklist.
+        when (blocklist) {
+            BLOCKED_REQUESTS -> blockedRequests++
+            EASYLIST -> easyListBlockedRequests++
+            EASYPRIVACY -> easyPrivacyBlockedRequests++
+            FANBOYS_ANNOYANCE_LIST -> fanboysAnnoyanceListBlockedRequests++
+            FANBOYS_SOCIAL_BLOCKING_LIST -> fanboysSocialBlockingListBlockedRequests++
+            ULTRALIST -> ultraListBlockedRequests++
+            ULTRAPRIVACY -> ultraPrivacyBlockedRequests++
+            THIRD_PARTY_REQUESTS -> thirdPartyBlockedRequests++
+        }
+    }
+
+    fun getRequestsCount(blocklist: Int): Int {
+        // Return the count of the indicated blocklist.
+        return when (blocklist) {
+            BLOCKED_REQUESTS -> blockedRequests
+            EASYLIST -> easyListBlockedRequests
+            EASYPRIVACY -> easyPrivacyBlockedRequests
+            FANBOYS_ANNOYANCE_LIST -> fanboysAnnoyanceListBlockedRequests
+            FANBOYS_SOCIAL_BLOCKING_LIST -> fanboysSocialBlockingListBlockedRequests
+            ULTRALIST -> ultraListBlockedRequests
+            ULTRAPRIVACY -> ultraPrivacyBlockedRequests
+            THIRD_PARTY_REQUESTS -> thirdPartyBlockedRequests
+            else -> 0 // Return 0.  This should never be called, but it is required by the return when statement.
+        }
+    }
+
+    fun resetRequestsCounters() {
+        // Reset all the resource request counters.
+        blockedRequests = 0
+        easyListBlockedRequests = 0
+        easyPrivacyBlockedRequests = 0
+        fanboysAnnoyanceListBlockedRequests = 0
+        fanboysSocialBlockingListBlockedRequests = 0
+        ultraListBlockedRequests = 0
+        ultraPrivacyBlockedRequests = 0
+        thirdPartyBlockedRequests = 0
+    }
+
+
+    // Publicly expose the scroll ranges.
+    fun getHorizontalScrollRange(): Int {
+        // Return the horizontal scroll range.
+        return computeHorizontalScrollRange()
+    }
+
+    fun getVerticalScrollRange(): Int {
+        // Return the vertical scroll range.
+        return computeVerticalScrollRange()
+    }
+
+
+    // Handle touches.
+    @SuppressLint("ClickableViewAccessibility")
+    override fun onTouchEvent(motionEvent: MotionEvent): Boolean {
+        // Run the commands for the given motion event action.
+        when (motionEvent.action) {
+            MotionEvent.ACTION_DOWN -> {
+                // Start nested scrolling along the vertical axis.  `ViewCompat` must be used until the minimum API >= 21.
+                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
+
+                // Save the current Y position.  Action down will not be called again until a new motion starts.
+                previousYPosition = motionEvent.y.toInt()
+            }
+            MotionEvent.ACTION_MOVE -> {
+                // Get the current Y position.
+                val currentYMotionPosition = motionEvent.y.toInt()
+
+                // Calculate the pre-scroll delta Y.
+                val preScrollDeltaY = previousYPosition - currentYMotionPosition
+
+                // Initialize a variable to track how much of the scroll is consumed.
+                val consumedScroll = IntArray(2)
+
+                // Initialize a variable to track the offset in the window.
+                val offsetInWindow = IntArray(2)
+
+                // Get the WebView Y position.
+                val webViewYPosition = scrollY
+
+                // Set the scroll delta Y to initially be the same as the pre-scroll delta Y.
+                var scrollDeltaY = preScrollDeltaY
+
+                // Dispatch the nested pre-school.  This scrolls the app bar if it needs it.  `offsetInWindow` will be returned with an updated value.
+                if (dispatchNestedPreScroll(0, preScrollDeltaY, consumedScroll, offsetInWindow)) {
+                    // Update the scroll delta Y if some of it was consumed.
+                    scrollDeltaY = preScrollDeltaY - consumedScroll[1]
+                }
+
+                // Check to see if the WebView is at the top and and the scroll action is downward.
+                if (webViewYPosition == 0 && scrollDeltaY < 0) {  // Swipe to refresh is being engaged.
+                    // Stop the nested scroll so that swipe to refresh has complete control.  This way releasing the scroll to refresh circle doesn't scroll the WebView at the same time.
+                    stopNestedScroll()
+                } else {  // Swipe to refresh is not being engaged.
+                    // Start the nested scroll so that the app bar can scroll off the screen.
+                    startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
+
+                    // Dispatch the nested scroll.  This scrolls the WebView.  The delta Y unconsumed normally controls the swipe refresh layout, but that is handled with the `if` statement above.
+                    dispatchNestedScroll(0, scrollDeltaY, 0, 0, offsetInWindow)
+
+                    // Store the current Y position for use in the next action move.
+                    previousYPosition -= scrollDeltaY
+                }
+            }
+            else -> stopNestedScroll()  // Stop nested scrolling.
+        }
+
+        // Perform a click.  This is required by the Android accessibility guidelines.
+        performClick()
+
+        // Run the default commands and return the result.
+        return super.onTouchEvent(motionEvent)
+    }
+
+
+    // Save and restore state.
+    fun saveNestedScrollWebViewState(): Bundle {
+        // Create a saved state bundle.
+        val savedState = Bundle()
+
+        // Populate the saved state bundle.
+        savedState.putBoolean(DOMAIN_SETTINGS_APPLIED, domainSettingsApplied)
+        savedState.putInt(DOMAIN_SETTINGS_DATABASE_ID, domainSettingsDatabaseId)
+        savedState.putString(CURRENT_DOMAIN_NAME, currentDomainName)
+        savedState.putString(CURRENT_URl, currentUrl)
+        savedState.putBoolean(ACCEPT_COOKIES, acceptCookies)
+        savedState.putBoolean(EASYLIST_ENABLED, easyListEnabled)
+        savedState.putBoolean(EASYPRIVACY_ENABLED, easyPrivacyEnabled)
+        savedState.putBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED, fanboysAnnoyanceListEnabled)
+        savedState.putBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED, fanboysSocialBlockingListEnabled)
+        savedState.putBoolean(ULTRALIST_ENABLED, ultraListEnabled)
+        savedState.putBoolean(ULTRAPRIVACY_ENABLED, ultraPrivacyEnabled)
+        savedState.putBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests)
+        savedState.putBoolean(HAS_PINNED_SSL_CERTIFICATE, hasPinnedSslCertificate)
+        savedState.putString(PINNED_SSL_ISSUED_TO_CNAME, pinnedSslIssuedToCName)
+        savedState.putString(PINNED_SSL_ISSUED_TO_ONAME, pinnedSslIssuedToOName)
+        savedState.putString(PINNED_SSL_ISSUED_TO_UNAME, pinnedSslIssuedToUName)
+        savedState.putString(PINNED_SSL_ISSUED_BY_CNAME, pinnedSslIssuedByCName)
+        savedState.putString(PINNED_SSL_ISSUED_BY_ONAME, pinnedSslIssuedByOName)
+        savedState.putString(PINNED_SSL_ISSUED_BY_UNAME, pinnedSslIssuedByUName)
+        savedState.putLong(PINNED_SSL_START_DATE, pinnedSslStartDate.time)
+        savedState.putLong(PINNED_SSL_END_DATE, pinnedSslEndDate.time)
+        savedState.putString(PINNED_IP_ADDRESSES, pinnedIpAddresses)
+        savedState.putBoolean(IGNORE_PINNED_DOMAIN_INFORMATION, ignorePinnedDomainInformation)
+        savedState.putBoolean(SWIPE_TO_REFRESH, swipeToRefresh)
+        savedState.putBoolean(JAVASCRIPT_ENABLED, this.settings.javaScriptEnabled)
+        savedState.putBoolean(DOM_STORAGE_ENABLED, this.settings.domStorageEnabled)
+        savedState.putString(USER_AGENT, this.settings.userAgentString)
+        savedState.putBoolean(WIDE_VIEWPORT, this.settings.useWideViewPort)
+        savedState.putInt(FONT_SIZE, this.settings.textZoom)
+
+        // Return the saved state bundle.
+        return savedState
+    }
+
+    fun restoreNestedScrollWebViewState(savedState: Bundle) {
+        // Restore the class variables.
+        domainSettingsApplied = savedState.getBoolean(DOMAIN_SETTINGS_APPLIED)
+        domainSettingsDatabaseId = savedState.getInt(DOMAIN_SETTINGS_DATABASE_ID)
+        currentDomainName = savedState.getString(CURRENT_DOMAIN_NAME)!!
+        currentUrl = savedState.getString(CURRENT_URl)!!
+        acceptCookies = savedState.getBoolean(ACCEPT_COOKIES)
+        easyListEnabled = savedState.getBoolean(EASYLIST_ENABLED)
+        easyPrivacyEnabled = savedState.getBoolean(EASYPRIVACY_ENABLED)
+        fanboysAnnoyanceListEnabled = savedState.getBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED)
+        fanboysSocialBlockingListEnabled = savedState.getBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED)
+        ultraListEnabled = savedState.getBoolean(ULTRALIST_ENABLED)
+        ultraPrivacyEnabled = savedState.getBoolean(ULTRAPRIVACY_ENABLED)
+        blockAllThirdPartyRequests = savedState.getBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS)
+        hasPinnedSslCertificate = savedState.getBoolean(HAS_PINNED_SSL_CERTIFICATE)
+        pinnedSslIssuedToCName = savedState.getString(PINNED_SSL_ISSUED_TO_CNAME)!!
+        pinnedSslIssuedToOName = savedState.getString(PINNED_SSL_ISSUED_TO_ONAME)!!
+        pinnedSslIssuedToUName = savedState.getString(PINNED_SSL_ISSUED_TO_UNAME)!!
+        pinnedSslIssuedByCName = savedState.getString(PINNED_SSL_ISSUED_BY_CNAME)!!
+        pinnedSslIssuedByOName = savedState.getString(PINNED_SSL_ISSUED_BY_ONAME)!!
+        pinnedSslIssuedByUName = savedState.getString(PINNED_SSL_ISSUED_BY_UNAME)!!
+        pinnedSslStartDate = Date(savedState.getLong(PINNED_SSL_START_DATE))
+        pinnedSslEndDate = Date(savedState.getLong(PINNED_SSL_END_DATE))
+        pinnedIpAddresses = savedState.getString(PINNED_IP_ADDRESSES)!!
+        ignorePinnedDomainInformation = savedState.getBoolean(IGNORE_PINNED_DOMAIN_INFORMATION)
+        swipeToRefresh = savedState.getBoolean(SWIPE_TO_REFRESH)
+        this.settings.javaScriptEnabled = savedState.getBoolean(JAVASCRIPT_ENABLED)
+        this.settings.domStorageEnabled = savedState.getBoolean(DOM_STORAGE_ENABLED)
+        this.settings.userAgentString = savedState.getString(USER_AGENT)
+        this.settings.useWideViewPort = savedState.getBoolean(WIDE_VIEWPORT)
+        this.settings.textZoom = savedState.getInt(FONT_SIZE)
+    }
+
+
+    // Method from NestedScrollingChild.
+    override fun setNestedScrollingEnabled(status: Boolean) {
+        // Set the status of the nested scrolling.
+        nestedScrollingChildHelper.isNestedScrollingEnabled = status
+    }
+
+    // Method from NestedScrollingChild.
+    override fun isNestedScrollingEnabled(): Boolean {
+        // Return the status of nested scrolling.
+        return nestedScrollingChildHelper.isNestedScrollingEnabled
+    }
+
+    // Method from NestedScrollingChild.
+    override fun startNestedScroll(axes: Int): Boolean {
+        // Start a nested scroll along the indicated axes.
+        return nestedScrollingChildHelper.startNestedScroll(axes)
+    }
+
+    // Method from NestedScrollingChild2.
+    override fun startNestedScroll(axes: Int, type: Int): Boolean {
+        // Start a nested scroll along the indicated axes for the given type of input which caused the scroll event.
+        return nestedScrollingChildHelper.startNestedScroll(axes, type)
+    }
+
+    // Method from NestedScrollingChild.
+    override fun stopNestedScroll() {
+        // Stop the nested scroll.
+        nestedScrollingChildHelper.stopNestedScroll()
+    }
+
+    // Method from NestedScrollingChild2.
+    override fun stopNestedScroll(type: Int) {
+        // Stop the nested scroll of the given type of input which caused the scroll event.
+        nestedScrollingChildHelper.stopNestedScroll(type)
+    }
+
+    // Method from NestedScrollingChild.
+    override fun hasNestedScrollingParent(): Boolean {
+        // Return the status of the nested scrolling parent.
+        return nestedScrollingChildHelper.hasNestedScrollingParent()
+    }
+
+    // Method from NestedScrollingChild2.
+    override fun hasNestedScrollingParent(type: Int): Boolean {
+        // return the status of the nested scrolling parent for the given type of input which caused the scroll event.
+        return nestedScrollingChildHelper.hasNestedScrollingParent(type)
+    }
+
+    // Method from NestedScrollingChild.
+    override fun dispatchNestedPreScroll(deltaX: Int, deltaY: Int, consumed: IntArray?, offsetInWindow: IntArray?): Boolean {
+        // Dispatch a nested pre-scroll with the specified deltas, which lets a parent to consume some of the scroll if desired.
+        return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow)
+    }
+
+    // Method from NestedScrollingChild2.
+    override fun dispatchNestedPreScroll(deltaX: Int, deltaY: Int, consumed: IntArray?, offsetInWindow: IntArray?, type: Int): Boolean {
+        // Dispatch a nested pre-scroll with the specified deltas for the given type of input which caused the scroll event, which lets a parent to consume some of the scroll if desired.
+        return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow, type)
+    }
+
+    // Method from NestedScrollingChild.
+    override fun dispatchNestedScroll(deltaXConsumed: Int, deltaYConsumed: Int, deltaXUnconsumed: Int, deltaYUnconsumed: Int, offsetInWindow: IntArray?): Boolean {
+        // Dispatch a nested scroll with the specified deltas.
+        return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow)
+    }
+
+    // Method from NestedScrollingChild2.
+    override fun dispatchNestedScroll(deltaXConsumed: Int, deltaYConsumed: Int, deltaXUnconsumed: Int, deltaYUnconsumed: Int, offsetInWindow: IntArray?, type: Int): Boolean {
+        // Dispatch a nested scroll with the specified deltas for the given type of input which caused the scroll event.
+        return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow, type)
+    }
+
+    // Method from NestedScrollingChild.
+    override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean {
+        // Dispatch a nested pre-fling with the specified velocity, which lets a parent consume the fling if desired.
+        return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY)
+    }
+
+    // Method from NestedScrollingChild.
+    override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
+        // Dispatch a nested fling with the specified velocity.
+        return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed)
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NoSwipeViewPager.java b/app/src/main/java/com/stoutner/privacybrowser/views/NoSwipeViewPager.java
deleted file mode 100644 (file)
index cb6e065..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright © 2019 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.views;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.viewpager.widget.ViewPager;
-
-public class NoSwipeViewPager extends ViewPager {
-    // The basic constructor
-    public NoSwipeViewPager(@NonNull Context context) {
-        // Roll up to the full constructor.
-        this(context, null);
-    }
-
-    // The full constructor.
-    public NoSwipeViewPager(@NonNull Context context, @Nullable AttributeSet attributeSet) {
-        // Run the default commands.
-        super(context, attributeSet);
-    }
-
-    // It is necessary to override `performClick()` when overriding `onTouchEvent()`
-    @Override
-    public boolean performClick() {
-        // Run the default commands.
-        super.performClick();
-
-        // Do not consume the events.
-        return false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        // `onTouchEvent()` requires calling `performClick()`.
-        performClick();
-
-        // Do not allow swiping.
-        return false;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        // Do not allow swiping.
-        return false;
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NoSwipeViewPager.kt b/app/src/main/java/com/stoutner/privacybrowser/views/NoSwipeViewPager.kt
new file mode 100644 (file)
index 0000000..6f61b08
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2019,2021 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+
+import androidx.viewpager.widget.ViewPager
+
+import kotlin.jvm.JvmOverloads
+
+class NoSwipeViewPager
+@JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null) : ViewPager(context, attributeSet) {
+    // It is necessary to override `performClick()` when overriding `onTouchEvent()`
+    override fun performClick(): Boolean {
+        // Run the default commands.
+        super.performClick()
+
+        // Do not consume the events.
+        return false
+    }
+
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        // `onTouchEvent()` requires calling `performClick()`.
+        performClick()
+
+        // Do not allow swiping.
+        return false
+    }
+
+    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
+        // Do not allow swiping.
+        return false
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/WrapVerticalContentViewPager.java b/app/src/main/java/com/stoutner/privacybrowser/views/WrapVerticalContentViewPager.java
deleted file mode 100644 (file)
index 7e29725..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright © 2017,2019 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.views;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-
-import androidx.viewpager.widget.ViewPager;
-
-public class WrapVerticalContentViewPager extends ViewPager {
-    // Setup the default constructors.
-    public WrapVerticalContentViewPager(Context context) {
-        super(context);
-    }
-
-    public WrapVerticalContentViewPager(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // Perform an initial `super.onMeasure`, which populates `getChildCount`.
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        // Initialize `maximumHeight`.
-        int maximumHeight = 0;
-
-        // Find the maximum height of each of the child views.
-        for (int i = 0; i < getChildCount(); i++) {
-            View childView = getChildAt(i);
-
-            // Measure the child view height with no constraints.
-            childView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-
-            // Store the child's height if it is larger than `maximumHeight`.
-            if (childView.getMeasuredHeight() > maximumHeight) {
-                maximumHeight = childView.getMeasuredHeight();
-            }
-        }
-
-        // Perform a final `super.onMeasure` to set the `maximumHeight`.
-        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maximumHeight, MeasureSpec.EXACTLY));
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/WrapVerticalContentViewPager.kt b/app/src/main/java/com/stoutner/privacybrowser/views/WrapVerticalContentViewPager.kt
new file mode 100644 (file)
index 0000000..0d1f0ff
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2017,2019,2021 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.views
+
+import android.content.Context
+import android.util.AttributeSet
+
+import androidx.viewpager.widget.ViewPager
+
+class WrapVerticalContentViewPager : ViewPager {
+    // The constructors.
+    constructor(context: Context) : super(context)
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        // Perform an initial `super.onMeasure`, which populates the child count.
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+        // Initialize the maximum height variable.
+        var maximumHeight = 0
+
+        // Find the maximum height of each of the child views.
+        for (i in 0 until childCount) {
+            // Get the child view.
+            val childView = getChildAt(i)
+
+            // Measure the child view height with no constraints.
+            childView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
+
+            // Store the child's height if it is larger than the maximum height.
+            if (childView.measuredHeight > maximumHeight) {
+                maximumHeight = childView.measuredHeight
+            }
+        }
+
+        // Perform a final `super.onMeasure` to set the maximum height.
+        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maximumHeight, MeasureSpec.EXACTLY))
+    }
+}
\ No newline at end of file
index 623178381a67cc9cc77b36d572695e87d9b30d9d..afe0520891d01af7c0e46427bb3114cc353b7d37 100644 (file)
@@ -26,8 +26,8 @@ buildscript {
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.2.1'
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
+        classpath 'com.android.tools.build:gradle:7.0.0'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21"
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
index 0351e0c489154002717585ee19356b8320254c37..d74feb70add84c2dfd292d4975c68a6f19559b6f 100644 (file)
@@ -1,14 +1,14 @@
-• Add an option to move the app bar to the bottom.
-• Reimplement the saving of web archives.
-• Reimplement the option to use an external app to download files.
-• Add fallbacks to open alternate download managers.
-• Add Monocles to the list of search engines.
-• Remove Do Not Track and third-party cookies.
-• Offer to open content URLs shared by other apps.
-• Handle content URLs and untrusted SSL certificates in View Source.
-• Fix UI freezing while downloading on some devices.
-• Fix a few rare crashes.
-• Make minor improvements to the user interface.
+• Ajout d'une option pour déplacer la barre des apps en bas.
+• Ré-implémentation de la sauvegarde des archives web.
+• Ré-implémentation de l'option d'utiliser une application externe pour télécharger des fichiers.
+• Ajout de fallbacks pour ouvrir des gestionnaires de téléchargement alternatifs.
+• Ajout de Monocles à la liste des moteurs de recherche.
+• Suppression de Do Not Track et des cookies tiers.
+• Offrir d'ouvrir les contenus d'URLs partagés par d'autres apps.
+• Gestion des URLs de contenu et des certificats SSL non fiables dans View Source.
+• Correction d'un gel de l'interface utilisateur lors du téléchargement sur certains appareils.
+• Correction de quelques rares crash.
+• Quelques améliorations mineures de l'interface utilisateur.
 • Traduction française mise à jour fournie par Kévin L.
 • Traduction portugaise brésilienne mise à jour fournie par Thiago Nazareno Conceição Silva de Jesus.
 • Traduction allemande mise à jour fournie par Bernhard G. Keller.
index 57a8d60c64a61e9269b56ec4885171e7fbf24b69..4998ab0d5f25dd083269b0a0b5fb45cd0b62d9f3 100644 (file)
@@ -1,6 +1,6 @@
-• Remove Startpage and make Mojeek the default homepage and search engine.
-• Invert the navigation menu when the app bar is on the bottom.
-• Show the bottom app bar when a new tab loads.
-• Limit content intent filters to text, images, and MHT files.
-• Fix some rare crashes.
+• Suppression de Startpage et passage de Mojeek en page d'accueil et moteur de recherche par défaut.
+• Inversion du menu de navigation lorsque la barre des apps est en bas.
+• Affichage de la barre d'apps inférieure lorsqu'un nouvel onglet se charge.
+• Limitation des filtres d'intention de contenu au texte, aux images et aux fichiers MHT.
+• Correction de certains rare crashs.
 • Traduction française mise à jour fournie par Kévin L.
\ No newline at end of file
index 85d1a808ab0f1623fd1d02cc673c4a1c1cf5fb54..d04947f2d7d51e4a5ba910e606a4229c84f5a3c2 100644 (file)
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip