// 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'
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'
</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>
</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>
</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>
</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>
<!--
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>.
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>
</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>
</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>
</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>
</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>
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;
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);
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) {
// 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());
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();
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();
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();
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();
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();
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();
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();
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();
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.
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();
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);
}
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);
// 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();
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.
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();
@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));
// Clear any pinned SSL certificate or IP addresses.
nestedScrollWebView.clearPinnedSslCertificate();
- nestedScrollWebView.clearPinnedIpAddresses();
+ nestedScrollWebView.setPinnedIpAddresses("");
// Reset the favorite icon if specified.
if (resetTab) {
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));
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();
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());
}
}
+ @SuppressLint("ClickableViewAccessibility")
@Override
public void initializeWebView(NestedScrollWebView nestedScrollWebView, int pageNumber, ProgressBar progressBar, String url, Boolean restoringState) {
// Get a handle for the shared preferences.
// 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));
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);
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});
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
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);
}
// Reset the list of host IP addresses.
- nestedScrollWebView.clearCurrentIpAddresses();
+ nestedScrollWebView.setCurrentIpAddresses("");
// Get a URI for the current URL.
Uri currentUri = Uri.parse(url);
/*
- * 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>.
*
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;
}
// 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<*>
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 {
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);
}
}
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;
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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
// 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.
// 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()
// 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()
}
}
- 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
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)
}
// 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)
// 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.
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.
}
// 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)
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
// 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"
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
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()
// 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.
} 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) {
}
}
+ // 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)
// 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) {
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;
}
// 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) ||
+++ /dev/null
-/*
- * 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;
- }
-}
--- /dev/null
+/*
+ * 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
+++ /dev/null
-/*
- * 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
--- /dev/null
+/*
+ * 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
+++ /dev/null
-/*
- * 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
--- /dev/null
+/*
+ * 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
+++ /dev/null
-/*
- * 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
--- /dev/null
+/*
+ * 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
}
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
-• 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.
-• 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
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