From: Soren Stoutner <soren@stoutner.com> Date: Tue, 6 Feb 2018 04:38:53 +0000 (-0700) Subject: Add Russian strings translation. Partial EasyList Implementation. X-Git-Tag: v2.8~4 X-Git-Url: https://gitweb.stoutner.com/?a=commitdiff_plain;h=f85107c894bdb2311c0ba86313daaa0378c0bb16;p=PrivacyBrowserAndroid.git Add Russian strings translation. Partial EasyList Implementation. --- diff --git a/.gitignore b/.gitignore index 6fe79936..c8173b9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .gradle /local.properties +/.idea/caches /.idea/workspace.xml /.idea/libraries .DS_Store diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml index 9d3a0900..d102bb3e 100644 --- a/.idea/codeStyleSettings.xml +++ b/.idea/codeStyleSettings.xml @@ -3,6 +3,7 @@ <component name="ProjectCodeStyleSettingsManager"> <option name="PER_PROJECT_SETTINGS"> <value> + <option name="LINE_SEPARATOR" value=" " /> <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND"> @@ -35,9 +36,6 @@ <option name="USE_CUSTOM_SETTINGS" value="true" /> </AndroidXmlCodeStyleSettings> <Objective-C-extensions> - <option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" /> - <option name="RELEASE_STYLE" value="IVAR" /> - <option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" /> <file> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" /> diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..ae45a4a8 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,222 @@ +<component name="ProjectCodeStyleConfiguration"> + <code_scheme name="Project" version="173"> + <option name="RIGHT_MARGIN" value="100" /> + <AndroidXmlCodeStyleSettings> + <option name="USE_CUSTOM_SETTINGS" value="true" /> + </AndroidXmlCodeStyleSettings> + <JavaCodeStyleSettings> + <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> + <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> + <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND"> + <value /> + </option> + <option name="IMPORT_LAYOUT_TABLE"> + <value> + <package name="android" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="com" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="junit" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="net" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="org" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="java" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="javax" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="" withSubpackages="true" static="true" /> + <emptyLine /> + </value> + </option> + </JavaCodeStyleSettings> + <Objective-C-extensions> + <file> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" /> + </file> + <class> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" /> + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" /> + </class> + <extensions> + <pair source="cpp" header="h" fileNamingConvention="NONE" /> + <pair source="c" header="h" fileNamingConvention="NONE" /> + </extensions> + </Objective-C-extensions> + <XML> + <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> + </XML> + <codeStyleSettings language="XML"> + <option name="FORCE_REARRANGE_MODE" value="1" /> + <indentOptions> + <option name="CONTINUATION_INDENT_SIZE" value="4" /> + </indentOptions> + <arrangement> + <rules> + <section> + <rule> + <match> + <AND> + <NAME>xmlns:android</NAME> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>xmlns:.*</NAME> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:id</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:name</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>name</NAME> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>style</NAME> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*</NAME> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:layout_width</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:layout_height</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:layout_.*</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:width</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:height</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*</NAME> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*</NAME> + <XML_NAMESPACE>.*</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + </rules> + </arrangement> + </codeStyleSettings> + </code_scheme> +</component> \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ +<component name="ProjectCodeStyleConfiguration"> + <state> + <option name="USE_PER_PROJECT_SETTINGS" value="true" /> + </state> +</component> \ No newline at end of file diff --git a/.idea/dictionaries/soren.xml b/.idea/dictionaries/soren.xml index 02429b2f..4205b54d 100644 --- a/.idea/dictionaries/soren.xml +++ b/.idea/dictionaries/soren.xml @@ -87,6 +87,7 @@ <w>parameterized</w> <w>parentfolder</w> <w>pinnedsslcertificate</w> + <w>privacybrowser</w> <w>programatically</w> <w>proxying</w> <w>qwant</w> @@ -116,6 +117,7 @@ <w>sslissuedtoorganization</w> <w>sslissuedtoorganizationalunit</w> <w>sslstartdate</w> + <w>stoutner</w> <w>subdomain</w> <w>subdomains</w> <w>subfolders</w> @@ -136,6 +138,7 @@ <w>verizons</w> <w>webkay</w> <w>webkitversion</w> + <w>websocket</w> <w>whatismyip</w> <w>wouldn</w> <w>yoyo</w> diff --git a/.idea/misc.xml b/.idea/misc.xml index 4a0c9c49..75dac502 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,8 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> - <component name="EntryPointsManager"> - <entry_points version="2.0" /> - </component> <component name="NullableNotNullManager"> <option name="myDefaultNullable" value="android.support.annotation.Nullable" /> <option name="myDefaultNotNull" value="android.support.annotation.NonNull" /> diff --git a/app/build.gradle b/app/build.gradle index 8644364d..c181e0cf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,11 +20,11 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 26 - buildToolsVersion '26.0.3' + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { minSdkVersion 19 - targetSdkVersion 26 + targetSdkVersion 27 versionCode 29 versionName "2.7.2" } @@ -65,7 +65,7 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support:design:26.1.0' + implementation 'com.android.support:design:27.0.2' // Only compile `com.google.firebase:firebase-ads` for the free flavor. freeImplementation 'com.google.firebase:firebase-ads:11.8.0' } diff --git a/app/src/main/assets/es/about_privacy_policy_dark.html b/app/src/main/assets/es/about_privacy_policy_dark.html index e37a58bf..138a7c45 100644 --- a/app/src/main/assets/es/about_privacy_policy_dark.html +++ b/app/src/main/assets/es/about_privacy_policy_dark.html @@ -82,8 +82,7 @@ <p>Los usuarios pueden elegir enviar comunicaciones directas a Stoutner, como mensajes de correo electrónico y comentarios en <a href="https://www.stoutner.com/">stoutner.com</a>.</p> <h3>Uso de Información</h3> - <p><strong class="blue">Stoutner puede usar esta información de cualquier forma que ayude en el desarrollo de Navegador Privado, - como solucionar problemas de informes de errores o en el desarrollo de caracterÃsticas, incluyendo compartir la información con una tercera parte para ayudar en este proceso.</strong> + <p><strong class="blue">Stoutner puede utilizar esta información para ayudar en el desarrollo de Navegador Privado y comunicar el estado del proyecto a los usuarios.</strong> <strong class="red">Stoutner nunca vendrá la información ni la transferirá a ninguna tercera parte que la pudiera usar para publicidad o marketing.</strong></p> <hr /> diff --git a/app/src/main/assets/es/about_privacy_policy_light.html b/app/src/main/assets/es/about_privacy_policy_light.html index c5c6609d..820083c7 100644 --- a/app/src/main/assets/es/about_privacy_policy_light.html +++ b/app/src/main/assets/es/about_privacy_policy_light.html @@ -82,8 +82,7 @@ <p>Los usuarios pueden elegir enviar comunicaciones directas a Stoutner, como mensajes de correo electrónico y comentarios en <a href="https://www.stoutner.com/">stoutner.com</a>.</p> <h3>Uso de Información</h3> - <p><strong class="blue">Stoutner puede usar esta información de cualquier forma que ayude en el desarrollo de Navegador Privado, - como solucionar problemas de informes de errores o en el desarrollo de caracterÃsticas, incluyendo compartir la información con una tercera parte para ayudar en este proceso.</strong> + <p><strong class="blue">Stoutner puede utilizar esta información para ayudar en el desarrollo de Navegador Privado y comunicar el estado del proyecto a los usuarios.</strong> <strong class="red">Stoutner nunca vendrá la información ni la transferirá a ninguna tercera parte que la pudiera usar para publicidad o marketing.</strong></p> <hr /> diff --git a/app/src/main/assets/it/about_changelog_dark.html b/app/src/main/assets/it/about_changelog_dark.html index 79657c35..ed351893 100644 --- a/app/src/main/assets/it/about_changelog_dark.html +++ b/app/src/main/assets/it/about_changelog_dark.html @@ -180,7 +180,7 @@ </ul> <h3>1.14.1 (versione codice 17)</h3> - <p><a href="https://git.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=5bd318993ebf675433f514dd04fc3e29545c9312">4 January 2017</a> - minima API 19, target API 25</p> + <p><a href="https://git.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=5bd318993ebf675433f514dd04fc3e29545c9312">4 Gennaio 2017</a> - minima API 19, target API 25</p> <ul> <li>Fix a bug that caused Privacy Browser to <a href="https://redmine.stoutner.com/issues/80">crash on some websites</a> when ad blocking was enabled.</li> </ul> diff --git a/app/src/main/assets/it/about_changelog_light.html b/app/src/main/assets/it/about_changelog_light.html index 3b71ff8b..c6bb6413 100644 --- a/app/src/main/assets/it/about_changelog_light.html +++ b/app/src/main/assets/it/about_changelog_light.html @@ -180,7 +180,7 @@ </ul> <h3>1.14.1 (versione codice 17)</h3> - <p><a href="https://git.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=5bd318993ebf675433f514dd04fc3e29545c9312">4 January 2017</a> - minima API 19, target API 25</p> + <p><a href="https://git.stoutner.com/?p=PrivacyBrowser.git;a=commitdiff;h=5bd318993ebf675433f514dd04fc3e29545c9312">4 Gennaio 2017</a> - minima API 19, target API 25</p> <ul> <li>Fix a bug that caused Privacy Browser to <a href="https://redmine.stoutner.com/issues/80">crash on some websites</a> when ad blocking was enabled.</li> </ul> diff --git a/app/src/main/assets/it/about_privacy_policy_dark.html b/app/src/main/assets/it/about_privacy_policy_dark.html index aa420fe0..372d2770 100644 --- a/app/src/main/assets/it/about_privacy_policy_dark.html +++ b/app/src/main/assets/it/about_privacy_policy_dark.html @@ -83,11 +83,10 @@ <h3>Utilizzo delle informazioni</h3> - <p><strong class="blue">Stoutner si riserva l'utilizzo di queste informazioni come supporto per lo sviluppo di Privacy Browser, ovvero per la correzione di bug o lo sviluppo di nuove funzionalità , - con la possibilità di condividerle con terze parti che forniscano assistenza per queste attività .</strong> + <p><strong class="blue">Stoutner si riserva l'utilizzo di queste informazioni come supporto per lo sviluppo di Privacy Browser e per comunicazioni sullo stato del progetto verso gli utenti.</strong> <strong class="red">Stoutner non rivenderà o comunque non trasferirà mai nessuna informazione a terze parti che potrebbero utilizzarle a scopi pubblicitari o di marketing.</strong></p> <hr /> - <p style="text-align: center;"><em>Revisione 1.5, 20 Aprile 2017</em></p> + <p style="text-align: center;"><em>Revisione 1.5, 11 Gennaio 2018</em></p> </body> </html> \ No newline at end of file diff --git a/app/src/main/assets/it/about_privacy_policy_light.html b/app/src/main/assets/it/about_privacy_policy_light.html index fcaf6db0..aca6756f 100644 --- a/app/src/main/assets/it/about_privacy_policy_light.html +++ b/app/src/main/assets/it/about_privacy_policy_light.html @@ -83,11 +83,10 @@ <h3>Utilizzo delle informazioni</h3> - <p><strong class="blue">Stoutner si riserva l'utilizzo di queste informazioni come supporto per lo sviluppo di Privacy Browser, ovvero per la correzione di bug o lo sviluppo di nuove funzionalità , - con la possibilità di condividerle con terze parti che forniscano assistenza per queste attività .</strong> + <p><strong class="blue">Stoutner si riserva l'utilizzo di queste informazioni come supporto per lo sviluppo di Privacy Browser e per comunicazioni sullo stato del progetto verso gli utenti.</strong> <strong class="red">Stoutner non rivenderà o comunque non trasferirà mai nessuna informazione a terze parti che potrebbero utilizzarle a scopi pubblicitari o di marketing.</strong></p> <hr /> - <p style="text-align: center;"><em>Revisione 1.5, 20 Aprile 2017</em></p> + <p style="text-align: center;"><em>Revisione 1.5, 11 Gennaio 2018</em></p> </body> </html> \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index 9cb3a71a..cfe93f27 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -22,6 +22,7 @@ package com.stoutner.privacybrowser.activities; import android.annotation.SuppressLint; +import android.app.Activity; import android.app.DialogFragment; import android.app.DownloadManager; import android.content.BroadcastReceiver; @@ -137,29 +138,36 @@ import java.net.URLEncoder; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; // We need to use AppCompatActivity from android.support.v7.app.AppCompatActivity to have access to the SupportActionBar until the minimum API is >= 21. -public class MainWebViewActivity extends AppCompatActivity implements AddDomainDialog.AddDomainListener, CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener, CreateHomeScreenShortcutDialog.CreateHomeScreenSchortcutListener, - DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, EditBookmarkDialog.EditBookmarkListener, EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener, - NavigationView.OnNavigationItemSelectedListener, PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener { - - // `darkTheme` is public static so it can be accessed from `AboutActivity`, `GuideActivity`, `AddDomainDialog`, `SettingsActivity`, `DomainsActivity`, `DomainsListFragment`, `BookmarksActivity`, `BookmarksDatabaseViewActivity`, - // `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `DownloadFileDialog`, `DownloadImageDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `EditBookmarkDatabaseViewDialog`, `HttpAuthenticationDialog`, `MoveToFolderDialog`, - // `SslCertificateErrorDialog`, `UrlHistoryDialog`, `ViewSslCertificateDialog`, `CreateHomeScreenShortcutDialog`, and `OrbotProxyHelper`. It is also used in `onCreate()`, `applyAppSettings()`, `applyDomainSettings()`, and `updatePrivacyIcons()`. +public class MainWebViewActivity extends AppCompatActivity implements AddDomainDialog.AddDomainListener, CreateBookmarkDialog.CreateBookmarkListener, + CreateBookmarkFolderDialog.CreateBookmarkFolderListener, CreateHomeScreenShortcutDialog.CreateHomeScreenSchortcutListener, DownloadFileDialog.DownloadFileListener, + DownloadImageDialog.DownloadImageListener, EditBookmarkDialog.EditBookmarkListener, EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener, + NavigationView.OnNavigationItemSelectedListener, PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, + UrlHistoryDialog.UrlHistoryListener { + + // `darkTheme` is public static so it can be accessed from `AboutActivity`, `GuideActivity`, `AddDomainDialog`, `SettingsActivity`, `DomainsActivity`, `DomainsListFragment`, `BookmarksActivity`, + // `BookmarksDatabaseViewActivity`, `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `DownloadFileDialog`, `DownloadImageDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`, + // `EditBookmarkDatabaseViewDialog`, `HttpAuthenticationDialog`, `MoveToFolderDialog`, `SslCertificateErrorDialog`, `UrlHistoryDialog`, `ViewSslCertificateDialog`, `CreateHomeScreenShortcutDialog`, + // and `OrbotProxyHelper`. It is also used in `onCreate()`, `applyAppSettings()`, `applyDomainSettings()`, and `updatePrivacyIcons()`. public static boolean darkTheme; - // `favoriteIconBitmap` is public static so it can be accessed from `CreateHomeScreenShortcutDialog`, `BookmarksActivity`, `BookmarksDatabaseViewActivity`, `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `EditBookmarkDialog`, - // `EditBookmarkFolderDialog`, `EditBookmarkDatabaseViewDialog`, and `ViewSslCertificateDialog`. It is also used in `onCreate()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onCreateHomeScreenShortcutCreate()`, `onSaveEditBookmark()`, - // `onSaveEditBookmarkFolder()`, and `applyDomainSettings()`. + // `favoriteIconBitmap` is public static so it can be accessed from `CreateHomeScreenShortcutDialog`, `BookmarksActivity`, `BookmarksDatabaseViewActivity`, `CreateBookmarkDialog`, + // `CreateBookmarkFolderDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `EditBookmarkDatabaseViewDialog`, and `ViewSslCertificateDialog`. It is also used in `onCreate()`, + // `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onCreateHomeScreenShortcutCreate()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `applyDomainSettings()`. public static Bitmap favoriteIconBitmap; // `formattedUrlString` is public static so it can be accessed from `BookmarksActivity`, `CreateBookmarkDialog`, and `AddDomainDialog`. // It is also used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onCreateHomeScreenShortcutCreate()`, and `loadUrlFromTextBox()`. public static String formattedUrlString; - // `sslCertificate` is public static so it can be accessed from `DomainsActivity`, `DomainsListFragment`, `DomainSettingsFragment`, `PinnedSslCertificateMismatchDialog`, and `ViewSslCertificateDialog`. It is also used in `onCreate()`. + // `sslCertificate` is public static so it can be accessed from `DomainsActivity`, `DomainsListFragment`, `DomainSettingsFragment`, `PinnedSslCertificateMismatchDialog`, + // and `ViewSslCertificateDialog`. It is also used in `onCreate()`. public static SslCertificate sslCertificate; // `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`. @@ -186,8 +194,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // `easyListVersion` is public static so it can be accessed from `AboutTabFragment`. It is also used in `onCreate()`. public static String easyListVersion; - // `currentBookmarksFolder` is public static so it can be accessed from `BookmarksActivity`. It is also used in `onCreate()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and - // `loadBookmarksFolder()`. + // `currentBookmarksFolder` is public static so it can be accessed from `BookmarksActivity`. It is also used in `onCreate()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, + // `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`. public static String currentBookmarksFolder; // `domainSettingsDatabaseId` is public static so it can be accessed from `PinnedSslCertificateMismatchDialog`. It is also used in `onCreate()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. @@ -219,8 +227,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // `rootCoordinatorLayout` is used in `onCreate()` and `applyAppSettings()`. private CoordinatorLayout rootCoordinatorLayout; - // `mainWebView` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()` - // `onSslMismatchBack()`, and `setDisplayWebpageImages()`. + // `mainWebView` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, + // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, and `setDisplayWebpageImages()`. private WebView mainWebView; // `fullScreenVideoFrameLayout` is used in `onCreate()` and `onConfigurationChanged()`. @@ -400,40 +408,734 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Run the default commands. super.onCreate(savedInstanceState); - // **DEBUG** Log the beginning of the loading of the ad blocker. - Log.i("AdBlocker", "Begin loading ad blocker"); - - // Initialize `adServerSet`. - final Set<String> adServersSet = new HashSet<>(); - - // Load the list of ad servers into memory. + Log.i("BlockLists", "Begin populating block lists."); + + // Initialize the block lists. + List<String> mainWhiteList = new LinkedList<>(); + List<String[]> multiEntryWhiteList = new LinkedList<>(); + List<String> mainBlockList = new LinkedList<>(); + List<String> initialBlockList = new LinkedList<>(); + List<String> finalBlockList = new LinkedList<>(); + List<String[]> multiEntryBlockList = new LinkedList<>(); + List<String[]> multiEntryInitialBlockList = new LinkedList<>(); + List<String[]> multiEntryFinalBlockList = new LinkedList<>(); + List<String[]> domainBlockList = new LinkedList<>(); + List<String[]> domainInitialBlockList = new LinkedList<>(); + List<String[]> domainFinalBlockList = new LinkedList<>(); + List<String[]> domainMultiEntryBlockList = new LinkedList<>(); + List<String[]> domainRegularExpressionBlockList = new LinkedList<>(); + List<String> regularExpressionBlockList = new LinkedList<>(); + + // Populate the block lists. try { // Load `easylist.txt` into a `BufferedReader`. BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(getAssets().open("easylist.txt"))); - // Create a string for storing each ad server. - String adBlockerEntry; + // Create a string for storing the block list entries. + String blockListEntry; - // Populate `adServersSet`. - while ((adBlockerEntry = bufferedReader.readLine()) != null) { + // Parse EasyList. + while ((blockListEntry = bufferedReader.readLine()) != null) { //noinspection StatementWithEmptyBody - if (adBlockerEntry.contains("##") || adBlockerEntry.contains("#?#") || adBlockerEntry.contains("#@#") || adBlockerEntry.startsWith("[")) { + if (blockListEntry.contains("##") || blockListEntry.contains("#?#") || blockListEntry.contains("#@#") || blockListEntry.startsWith("[")) { // Entries that contain `##`, `#?#`, and `#@#` are for hiding elements in the main page's HTML. Entries that start with `[` describe the AdBlock compatibility level. // Do nothing. Privacy Browser does not currently use these entries. - // **DEBUG** Log the entries that are not added. - // Log.i("AdBlocker", "Not added: " + adBlockerEntry); - } else if (adBlockerEntry.startsWith("!")){ // Entries that begin with `!` are comments. - if (adBlockerEntry.startsWith("! Version:")) { + //Log.i("BlackLists", "Not added: " + adBlockerEntry); + } else if (blockListEntry.startsWith("!")){ // Entries that begin with `!` are comments. + if (blockListEntry.startsWith("! Version:")) { // Store the EasyList version number. - easyListVersion = adBlockerEntry.substring(11); + easyListVersion = blockListEntry.substring(11); } - // **DEBUG** Log the entries that are not added. - // Log.i("AdBlocker", "Not added: " + adBlockerEntry); - } else { - adServersSet.add(adBlockerEntry); + //Log.i("BlackLists", "Not added: " + adBlockerEntry); + } else if (blockListEntry.startsWith("@@")) { // Entries that begin with `@@` are excludes (whitelists). + // mainWhiteList.add(blockListEntry.substring(2)); + + //Log.i("BlockLists", "Main white list added: " + blockListEntry.substring(2, blockListEntry.length())); + } else if (blockListEntry.endsWith("|")){ // Entries that end with `|` match against the end of the URL. + // Strip out the final "|" + blockListEntry = blockListEntry.substring(0, blockListEntry.length() - 1); + + // Strip out any initial `||`. They are redundant in this case because the block list entry is being matched against the end of the URL. + if (blockListEntry.startsWith("||")) { + blockListEntry = blockListEntry.substring(2); + } + + if (blockListEntry.contains("*")) { + int wildcardIndex = blockListEntry.indexOf("*"); + + String firstEntry = blockListEntry.substring(0, wildcardIndex); + String secondEntry = blockListEntry.substring(wildcardIndex + 1); + + if (firstEntry.endsWith("^")) { + String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1); + + String firstEntry1 = firstEntryBase + ":"; + String firstEntry2 = firstEntryBase + "/"; + String firstEntry3 = firstEntryBase + "?"; + String firstEntry4 = firstEntryBase + "="; + String firstEntry5 = firstEntryBase + "&"; + + String[] doubleEntry1 = {firstEntry1, secondEntry}; + String[] doubleEntry2 = {firstEntry2, secondEntry}; + String[] doubleEntry3 = {firstEntry3, secondEntry}; + String[] doubleEntry4 = {firstEntry4, secondEntry}; + String[] doubleEntry5 = {firstEntry5, secondEntry}; + + multiEntryFinalBlockList.add(doubleEntry1); + multiEntryFinalBlockList.add(doubleEntry2); + multiEntryFinalBlockList.add(doubleEntry3); + multiEntryFinalBlockList.add(doubleEntry4); + multiEntryFinalBlockList.add(doubleEntry5); + + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry1 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry2 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry3 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry4 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry5 + " , " + secondEntry); + } else { + String[] doubleEntry = {firstEntry, secondEntry}; + + multiEntryFinalBlockList.add(doubleEntry); + + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry + " , " + secondEntry); + } + } else { + finalBlockList.add(blockListEntry); + + //Log.i("BlockLists", "Final block list added: " + blockListEntry); + } + } else if (blockListEntry.contains("$")) { // Entries that contain `$` use filter options. + // Strip out any initial `||`. These will be treated like any other entry. + if (blockListEntry.startsWith("||")) { + blockListEntry = blockListEntry.substring(2); + } + + if (blockListEntry.contains("third-party")) { + // Log.i("BlockLists", "Not added: " + blockListEntry); + } else if (blockListEntry.substring(blockListEntry.indexOf("$")).contains("domain")) { + if (blockListEntry.contains("~")) { // Whitelist. + + } else { + // Separate the filters. + String entry = blockListEntry.substring(0, blockListEntry.indexOf("$")); + String filters = blockListEntry.substring(blockListEntry.indexOf("$") + 1); + String domains = filters.substring(filters.indexOf("domain=") + 7); + + // Only process the block list item if the entry is not null. Some lines in EasyList begin with `$websocket`, which create a null entry. + if (!entry.equals("")) { + do { + String domain; + + if (domains.contains("|")) { + // Get the first domain. + domain = domains.substring(0, domains.indexOf("|")); + + // Remove the first domain from the list. + domains = domains.substring(domains.indexOf("|") + 1); + } else { + domain = domains; + } + + if (entry.contains("*")) { + int wildcardIndex = entry.indexOf("*"); + + String firstEntry = entry.substring(0, wildcardIndex); + String secondEntry = entry.substring(wildcardIndex + 1); + + if (firstEntry.endsWith("^")) { + String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1); + + String firstEntry1 = firstEntryBase + ":"; + String firstEntry2 = firstEntryBase + "/"; + String firstEntry3 = firstEntryBase + "?"; + String firstEntry4 = firstEntryBase + "="; + String firstEntry5 = firstEntryBase + "&"; + + String[] domainDoubleEntry1 = {domain, firstEntry1, secondEntry}; + String[] domainDoubleEntry2 = {domain, firstEntry2, secondEntry}; + String[] domainDoubleEntry3 = {domain, firstEntry3, secondEntry}; + String[] domainDoubleEntry4 = {domain, firstEntry4, secondEntry}; + String[] domainDoubleEntry5 = {domain, firstEntry5, secondEntry}; + + domainMultiEntryBlockList.add(domainDoubleEntry1); + domainMultiEntryBlockList.add(domainDoubleEntry2); + domainMultiEntryBlockList.add(domainDoubleEntry3); + domainMultiEntryBlockList.add(domainDoubleEntry4); + domainMultiEntryBlockList.add(domainDoubleEntry5); + + //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry1 + " , " + secondEntry); + //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry2 + " , " + secondEntry); + //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry3 + " , " + secondEntry); + //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry4 + " , " + secondEntry); + //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry5 + " , " + secondEntry); + } else { + String[] domainDoubleEntry = {domain, firstEntry, secondEntry}; + + domainMultiEntryBlockList.add(domainDoubleEntry); + + //Log.i("BlockLists", "Domain double entry block list added: " + domain + " , " + firstEntry + " , " + secondEntry); + } + } else if (entry.endsWith("^")) { + String entryBase = entry.substring(0, entry.length() - 1); + + String entry1 = entryBase + ":"; + String entry2 = entryBase + "/"; + String entry3 = entryBase + "?"; + String entry4 = entryBase + "="; + String entry5 = entryBase + "&"; + + String[] domainEntry1 = {domain, entry1}; + String[] domainEntry2 = {domain, entry2}; + String[] domainEntry3 = {domain, entry3}; + String[] domainEntry4 = {domain, entry4}; + String[] domainEntry5 = {domain, entry5}; + + domainBlockList.add(domainEntry1); + domainBlockList.add(domainEntry2); + domainBlockList.add(domainEntry3); + domainBlockList.add(domainEntry4); + domainBlockList.add(domainEntry5); + + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry1); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry2); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry3); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry4); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry5); + } else if (entry.startsWith("^")) { + String entryBase = entry.substring(1); + + String entry1 = ":" + entryBase; + String entry2 = ":" + entryBase; + String entry3 = ":" + entryBase; + String entry4 = ":" + entryBase; + String entry5 = ":" + entryBase; + + String[] domainEntry1 = {domain, entry1}; + String[] domainEntry2 = {domain, entry2}; + String[] domainEntry3 = {domain, entry3}; + String[] domainEntry4 = {domain, entry4}; + String[] domainEntry5 = {domain, entry5}; + + domainBlockList.add(domainEntry1); + domainBlockList.add(domainEntry2); + domainBlockList.add(domainEntry3); + domainBlockList.add(domainEntry4); + domainBlockList.add(domainEntry5); + + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry1); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry2); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry3); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry4); + //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry5); + } else if (entry.startsWith("|")) { + // Remove the initial `|`; + String entryBase = entry.substring(1); + + //noinspection StatementWithEmptyBody + if (entryBase.equals("http://") || entryBase.equals("https://")) { + // Do nothing. These entries will entirely block the website. + // Often the original entry blocks `$script` but Privacy Browser does not currently differentiate between scripts and other entries. + } else { + String[] domainEntry = {domain, entryBase}; + + domainInitialBlockList.add(domainEntry); + + //Log.i("BlockLists", "Domain initial block list added: " + domain + " , " + entryBase); + } + } else if (entry.endsWith("|")) { + // Remove the final `|`. + String entryBase = entry.substring(0, entry.length() - 1); + + String[] domainEntry = {domain, entryBase}; + + domainFinalBlockList.add(domainEntry); + + Log.i("BlockLists", "Domain final block list added: " + domain + " , " + entryBase); + } else if (entry.contains("\\")) { + String[] domainEntry = {domain, entry}; + + domainRegularExpressionBlockList.add(domainEntry); + + // Log.i("BlockLists", "Domain regular expression block list added: " + domain + " , " + entry); + } else { + String[] domainEntry = {domain, entry}; + + domainBlockList.add(domainEntry); + + //Log.i("BlockLists", "Domain block list added: " + domain + " , " + entry); + } + } while (domains.contains("|")); + } + } + } else if (blockListEntry.contains("~")) { // Whitelist entries. + // Remove the filter options. + blockListEntry = blockListEntry.substring(0, blockListEntry.indexOf("$")); + + // Strip any trailing `*`. + if (blockListEntry.endsWith("*")) { + blockListEntry = blockListEntry.substring(0, blockListEntry.length() -1); + } + + if (blockListEntry.contains("*")) { + int wildcardIndex = blockListEntry.indexOf("*"); + + String firstEntry = blockListEntry.substring(0, wildcardIndex); + String secondEntry = blockListEntry.substring(wildcardIndex + 1); + + if (firstEntry.endsWith("^")) { + String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1); + + String firstEntry1 = firstEntryBase + ":"; + String firstEntry2 = firstEntryBase + "/"; + String firstEntry3 = firstEntryBase + "?"; + String firstEntry4 = firstEntryBase + "="; + String firstEntry5 = firstEntryBase + "&"; + + String[] doubleEntry1 = {firstEntry1, secondEntry}; + String[] doubleEntry2 = {firstEntry2, secondEntry}; + String[] doubleEntry3 = {firstEntry3, secondEntry}; + String[] doubleEntry4 = {firstEntry4, secondEntry}; + String[] doubleEntry5 = {firstEntry5, secondEntry}; + + multiEntryWhiteList.add(doubleEntry1); + multiEntryWhiteList.add(doubleEntry2); + multiEntryWhiteList.add(doubleEntry3); + multiEntryWhiteList.add(doubleEntry4); + multiEntryWhiteList.add(doubleEntry5); + + //Log.i("BlockLists", "Multi entry white list added: " + firstEntry1 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry white list added: " + firstEntry2 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry white list added: " + firstEntry3 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry white list added: " + firstEntry4 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry white list added: " + firstEntry5 + " , " + secondEntry); + } else { + String[] doubleEntry = {firstEntry, secondEntry}; + + multiEntryWhiteList.add(doubleEntry); + + //Log.i("BlockLists", "Multi entry white list added: " + firstEntry + " , " + secondEntry); + } + } else { + if (blockListEntry.endsWith("^")) { + String blockListEntryBase = blockListEntry.substring(0, blockListEntry.length() - 1); + + String blockListEntry1 = blockListEntryBase + ":"; + String blockListEntry2 = blockListEntryBase + "/"; + String blockListEntry3 = blockListEntryBase + "?"; + String blockListEntry4 = blockListEntryBase + "="; + String blockListEntry5 = blockListEntryBase + "&"; + + mainWhiteList.add(blockListEntry1); + mainWhiteList.add(blockListEntry2); + mainWhiteList.add(blockListEntry3); + mainWhiteList.add(blockListEntry4); + mainWhiteList.add(blockListEntry5); + + // Log.i("BlockLists", "Main white list added: " + blockListEntry1); + // Log.i("BlockLists", "Main white list added: " + blockListEntry2); + // Log.i("BlockLists", "Main white list added: " + blockListEntry3); + // Log.i("BlockLists", "Main white list added: " + blockListEntry4); + // Log.i("BlockLists", "Main white list added: " + blockListEntry5); + } else { + mainWhiteList.add(blockListEntry); + + // Log.i("BlockLists", "Main white list added: " + blockListEntry); + } + } + } else if (blockListEntry.contains("\\")) { // Regular expressions. + // Remove the filter options. + blockListEntry = blockListEntry.substring(0, blockListEntry.indexOf("$")); + + regularExpressionBlockList.add(blockListEntry); + + //Log.i("BlockLists", "Regular expression list added: " + blockListEntry); + } else { + // Remove the filter options. + blockListEntry = blockListEntry.substring(0, blockListEntry.indexOf("$")); + + // Strip any trailing `*` or `^`. Many of these entries have `^$`, which seem redundant for the purposes of Privacy Browser. + if (blockListEntry.endsWith("*") || blockListEntry.endsWith("^")) { + blockListEntry = blockListEntry.substring(0, blockListEntry.length() - 1); + } + + if (blockListEntry.contains("*")) { // Use a multi entry list. + int wildcardIndex = blockListEntry.indexOf("*"); + + String firstEntry = blockListEntry.substring(0, wildcardIndex); + String secondEntry = blockListEntry.substring(wildcardIndex + 1); + + // Remove `.*` if it appears at the beginning of the second entry. + if (secondEntry.startsWith(".*")) { + secondEntry = secondEntry.substring(2); + } + + // Create a third entry if required. + if (secondEntry.contains("*")) { + wildcardIndex = secondEntry.indexOf("*"); + + String thirdEntry = secondEntry.substring(wildcardIndex + 1); + secondEntry = secondEntry.substring(0, wildcardIndex); + + if (firstEntry.endsWith("^")) { + String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1); + + String firstEntry1 = firstEntryBase + ":"; + String firstEntry2 = firstEntryBase + "/"; + String firstEntry3 = firstEntryBase + "?"; + String firstEntry4 = firstEntryBase + "="; + String firstEntry5 = firstEntryBase + "&"; + + if (thirdEntry.endsWith("|")) { + thirdEntry = thirdEntry.substring(0, thirdEntry.length() - 1); + + String[] tripleEntry1 = {firstEntry1, secondEntry, thirdEntry}; + String[] tripleEntry2 = {firstEntry2, secondEntry, thirdEntry}; + String[] tripleEntry3 = {firstEntry3, secondEntry, thirdEntry}; + String[] tripleEntry4 = {firstEntry4, secondEntry, thirdEntry}; + String[] tripleEntry5 = {firstEntry5, secondEntry, thirdEntry}; + + multiEntryFinalBlockList.add(tripleEntry1); + multiEntryFinalBlockList.add(tripleEntry2); + multiEntryFinalBlockList.add(tripleEntry3); + multiEntryFinalBlockList.add(tripleEntry4); + multiEntryFinalBlockList.add(tripleEntry5); + + //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry1 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry2 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry3 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry4 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry5 + " , " + secondEntry + " , " + thirdEntry); + } else { + String[] tripleEntry1 = {firstEntry1, secondEntry, thirdEntry}; + String[] tripleEntry2 = {firstEntry2, secondEntry, thirdEntry}; + String[] tripleEntry3 = {firstEntry3, secondEntry, thirdEntry}; + String[] tripleEntry4 = {firstEntry4, secondEntry, thirdEntry}; + String[] tripleEntry5 = {firstEntry5, secondEntry, thirdEntry}; + + multiEntryBlockList.add(tripleEntry1); + multiEntryBlockList.add(tripleEntry2); + multiEntryBlockList.add(tripleEntry3); + multiEntryBlockList.add(tripleEntry4); + multiEntryBlockList.add(tripleEntry5); + + //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry1 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry2 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry3 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry4 + " , " + secondEntry + " , " + thirdEntry); + //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry5 + " , " + secondEntry + " , " + thirdEntry); + } + } else { + String[] tripleEntry = {firstEntry, secondEntry, thirdEntry}; + + multiEntryBlockList.add(tripleEntry); + + // Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry + " , " + secondEntry + " , " + thirdEntry); + } + } else { // This is a double entry. + if (firstEntry.startsWith("|")) { + String[] doubleEntry = {firstEntry.substring(1), secondEntry}; + + multiEntryInitialBlockList.add(doubleEntry); + + //Log.i("BlockLists", "Multi entry initial block list added: " + firstEntry.substring(1) + " , " + secondEntry); + } else if (firstEntry.startsWith("^")) { + String firstEntryBase = firstEntry.substring(1); + + String firstEntry1 = ":" + firstEntryBase; + String firstEntry2 = "/" + firstEntryBase; + String firstEntry3 = "?" + firstEntryBase; + String firstEntry4 = "=" + firstEntryBase; + String firstEntry5 = "&" + firstEntryBase; + + String[] doubleEntry1 = {firstEntry1, secondEntry}; + String[] doubleEntry2 = {firstEntry2, secondEntry}; + String[] doubleEntry3 = {firstEntry3, secondEntry}; + String[] doubleEntry4 = {firstEntry4, secondEntry}; + String[] doubleEntry5 = {firstEntry5, secondEntry}; + + multiEntryBlockList.add(doubleEntry1); + multiEntryBlockList.add(doubleEntry2); + multiEntryBlockList.add(doubleEntry3); + multiEntryBlockList.add(doubleEntry4); + multiEntryBlockList.add(doubleEntry5); + + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry1 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry2 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry3 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry4 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry5 + " , " + secondEntry); + } else if (firstEntry.endsWith("^")) { + String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1); + + String firstEntry1 = firstEntryBase + ":"; + String firstEntry2 = firstEntryBase + "/"; + String firstEntry3 = firstEntryBase + "?"; + String firstEntry4 = firstEntryBase + "="; + String firstEntry5 = firstEntryBase + "&"; + + String[] doubleEntry1 = {firstEntry1, secondEntry}; + String[] doubleEntry2 = {firstEntry2, secondEntry}; + String[] doubleEntry3 = {firstEntry3, secondEntry}; + String[] doubleEntry4 = {firstEntry4, secondEntry}; + String[] doubleEntry5 = {firstEntry5, secondEntry}; + + multiEntryBlockList.add(doubleEntry1); + multiEntryBlockList.add(doubleEntry2); + multiEntryBlockList.add(doubleEntry3); + multiEntryBlockList.add(doubleEntry4); + multiEntryBlockList.add(doubleEntry5); + + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry1 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry2 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry3 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry4 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry5 + " , " + secondEntry); + } else if (secondEntry.startsWith("^")) { + String secondEntryBase = secondEntry.substring(1); + + String secondEntry1 = ":" + secondEntryBase; + String secondEntry2 = "/" + secondEntryBase; + String secondEntry3 = "?" + secondEntryBase; + String secondEntry4 = "=" + secondEntryBase; + String secondEntry5 = "&" + secondEntryBase; + + String[] doubleEntry1 = {firstEntry, secondEntry1}; + String[] doubleEntry2 = {firstEntry, secondEntry2}; + String[] doubleEntry3 = {firstEntry, secondEntry3}; + String[] doubleEntry4 = {firstEntry, secondEntry4}; + String[] doubleEntry5 = {firstEntry, secondEntry5}; + + multiEntryBlockList.add(doubleEntry1); + multiEntryBlockList.add(doubleEntry2); + multiEntryBlockList.add(doubleEntry3); + multiEntryBlockList.add(doubleEntry4); + multiEntryBlockList.add(doubleEntry5); + + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5); + } else if (secondEntry.endsWith("^")) { + String secondEntryBase = secondEntry.substring(0, secondEntry.length() - 1); + + String secondEntry1 = secondEntryBase + ":"; + String secondEntry2 = secondEntryBase + "/"; + String secondEntry3 = secondEntryBase + "?"; + String secondEntry4 = secondEntryBase + "="; + String secondEntry5 = secondEntryBase + "&"; + + String[] doubleEntry1 = {firstEntry, secondEntry1}; + String[] doubleEntry2 = {firstEntry, secondEntry2}; + String[] doubleEntry3 = {firstEntry, secondEntry3}; + String[] doubleEntry4 = {firstEntry, secondEntry4}; + String[] doubleEntry5 = {firstEntry, secondEntry5}; + + String[] doubleEntryFinal = {firstEntry, secondEntryBase}; + + multiEntryBlockList.add(doubleEntry1); + multiEntryBlockList.add(doubleEntry2); + multiEntryBlockList.add(doubleEntry3); + multiEntryBlockList.add(doubleEntry4); + multiEntryBlockList.add(doubleEntry5); + + multiEntryFinalBlockList.add(doubleEntryFinal); + + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5); + + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry + " , " + secondEntryBase); + } else { + String[] doubleEntry = {firstEntry, secondEntry}; + + multiEntryBlockList.add(doubleEntry); + + //Log.i("BlockLists", "Multi entry block list added: " + firstEntry + " , " + secondEntry); + } + } + } else if (blockListEntry.startsWith("|")) { // Populate the initial block list. + // Strip the initial `|`. + blockListEntry = blockListEntry.substring(1); + + // Populate the initial block list. + initialBlockList.add(blockListEntry); + + //Log.i("BlockLists", "Initial block list added: " + blockListEntry); + } else { // Populate the main block list. + mainBlockList.add(blockListEntry); + + //Log.i("BlockLists", "Main block list added: " + blockListEntry); + } + } + } else { // Populate the standard lists. + // Strip out any initial `||`. These will be treated like any other entry. + if (blockListEntry.startsWith("||")) { + blockListEntry = blockListEntry.substring(2); + } + + // Strip out any initial `*`. + if (blockListEntry.startsWith("*")) { + blockListEntry = blockListEntry.substring(1); + } + + // Strip out any trailing `*`. + if (blockListEntry.endsWith("*")) { + blockListEntry = blockListEntry.substring(0, blockListEntry.length() - 1); + } + + if (blockListEntry.contains("*")) { // Entries that contain a `*` in the middle have to be treated specially. + int wildcardIndex = blockListEntry.indexOf("*"); + + String firstEntry = blockListEntry.substring(0, wildcardIndex); + String secondEntry = blockListEntry.substring(wildcardIndex + 1); + + // Remove `.*` if it appears at the beginning of the second entry. + if (secondEntry.startsWith(".*")) { + secondEntry = secondEntry.substring(2); + } + + // Create a third entry if required. + if (secondEntry.contains("*")) { + wildcardIndex = secondEntry.indexOf("*"); + + String thirdEntry = secondEntry.substring(wildcardIndex + 1); + secondEntry = secondEntry.substring(0, wildcardIndex); + + String[] tripleEntry = {firstEntry, secondEntry, thirdEntry}; + + multiEntryBlockList.add(tripleEntry); + + //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry + " , " + secondEntry + " , " + thirdEntry); + } else { + if (firstEntry.startsWith("|")) { + String[] doubleEntry = {firstEntry.substring(1), secondEntry}; + + multiEntryInitialBlockList.add(doubleEntry); + + //Log.i("BlockLists", "Multi entry initial block list added: " + firstEntry.substring(1) + " , " + secondEntry); + } else if (firstEntry.startsWith("^")) { + String firstEntryBase = firstEntry.substring(1); + + String firstEntry1 = ":" + firstEntryBase; + String firstEntry2 = "/" + firstEntryBase; + String firstEntry3 = "?" + firstEntryBase; + String firstEntry4 = "=" + firstEntryBase; + String firstEntry5 = "&" + firstEntryBase; + + String[] doubleEntry1 = {firstEntry1, secondEntry}; + String[] doubleEntry2 = {firstEntry2, secondEntry}; + String[] doubleEntry3 = {firstEntry3, secondEntry}; + String[] doubleEntry4 = {firstEntry4, secondEntry}; + String[] doubleEntry5 = {firstEntry5, secondEntry}; + + multiEntryBlockList.add(doubleEntry1); + multiEntryBlockList.add(doubleEntry2); + multiEntryBlockList.add(doubleEntry3); + multiEntryBlockList.add(doubleEntry4); + multiEntryBlockList.add(doubleEntry5); + + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry1 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry2 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry3 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry4 + " , " + secondEntry); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry5 + " , " + secondEntry); + } else if (secondEntry.startsWith("^")) { + String secondEntryBase = secondEntry.substring(1); + + String secondEntry1 = ":" + secondEntryBase; + String secondEntry2 = "/" + secondEntryBase; + String secondEntry3 = "?" + secondEntryBase; + String secondEntry4 = "=" + secondEntryBase; + String secondEntry5 = "&" + secondEntryBase; + + String[] doubleEntry1 = {firstEntry, secondEntry1}; + String[] doubleEntry2 = {firstEntry, secondEntry2}; + String[] doubleEntry3 = {firstEntry, secondEntry3}; + String[] doubleEntry4 = {firstEntry, secondEntry4}; + String[] doubleEntry5 = {firstEntry, secondEntry5}; + + multiEntryBlockList.add(doubleEntry1); + multiEntryBlockList.add(doubleEntry2); + multiEntryBlockList.add(doubleEntry3); + multiEntryBlockList.add(doubleEntry4); + multiEntryBlockList.add(doubleEntry5); + + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5); + } else if (secondEntry.endsWith("^")) { + String secondEntryBase = secondEntry.substring(0, secondEntry.length() - 1); + + String secondEntry1 = secondEntryBase + ":"; + String secondEntry2 = secondEntryBase + "/"; + String secondEntry3 = secondEntryBase + "?"; + String secondEntry4 = secondEntryBase + "="; + String secondEntry5 = secondEntryBase + "&"; + + String[] doubleEntry1 = {firstEntry, secondEntry1}; + String[] doubleEntry2 = {firstEntry, secondEntry2}; + String[] doubleEntry3 = {firstEntry, secondEntry3}; + String[] doubleEntry4 = {firstEntry, secondEntry4}; + String[] doubleEntry5 = {firstEntry, secondEntry5}; + + String[] doubleEntryFinal = {firstEntry, secondEntryBase}; + + multiEntryBlockList.add(doubleEntry1); + multiEntryBlockList.add(doubleEntry2); + multiEntryBlockList.add(doubleEntry3); + multiEntryBlockList.add(doubleEntry4); + multiEntryBlockList.add(doubleEntry5); + + multiEntryFinalBlockList.add(doubleEntryFinal); + + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4); + //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5); + + //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry + " , " + secondEntryBase); + } else { + String[] doubleEntry = {firstEntry, secondEntry}; + + multiEntryBlockList.add(doubleEntry); + + //Log.i("BlockLists", "Multi entry block list added: " + firstEntry + " , " + secondEntry); + } + } + } else { + if (blockListEntry.endsWith("^")) { // `^` matches against `:`, `/`, `?`, `=`, `&`, and the end of the URL. + // Add all the variations to the main block list. + mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + ":"); + mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "/"); + mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "?"); + mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "="); + mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "&"); + + // Add the base block entry to the final block list. + finalBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1)); + + //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + ":"); + //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "/"); + //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "?"); + //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "="); + //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "&"); + //Log.i("BlockLists", "Final block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1)); + } else { // This is a basic entry. + // Add the modified block list entry to the main block list. + mainBlockList.add(blockListEntry); + + //Log.i("BlockLists", "Main block list added: " + blockListEntry); + } + } } } @@ -443,8 +1145,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // The asset exists, so the `IOException` will never be thrown. } - // **DEBUG** Log the finishing of the loading of the ad blocker. - Log.i("AdBlocker", "Finish loading ad blocker"); + Log.i("BlockLists", "Finish populating block lists"); // Set the content view. setContentView(R.layout.main_drawerlayout); @@ -625,7 +1326,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Set `rootCoordinatorLayout` to fit under the status and navigation bars. rootCoordinatorLayout.setFitsSystemWindows(false); - if (translucentNavigationBarOnFullscreen) { // There is an Android Support Library bug that causes a scrim to print on the right side of the `Drawer Layout` when the navigation bar is displayed on the right of the screen. + // There is an Android Support Library bug that causes a scrim to print on the right side of the `Drawer Layout` when the navigation bar is displayed on the right of the screen. + if (translucentNavigationBarOnFullscreen) { // Set the navigation bar to be translucent. getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); } @@ -812,15 +1514,15 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // The `DrawerListener` allows us to update the Navigation Menu. drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() { @Override - public void onDrawerSlide(View drawerView, float slideOffset) { + public void onDrawerSlide(@NonNull View drawerView, float slideOffset) { } @Override - public void onDrawerOpened(View drawerView) { + public void onDrawerOpened(@NonNull View drawerView) { } @Override - public void onDrawerClosed(View drawerView) { + public void onDrawerClosed(@NonNull View drawerView) { } @Override @@ -888,37 +1590,164 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD } } - // Block ads. We have to use the deprecated `shouldInterceptRequest` until minimum API >= 21. + // Check requests against the block lists. The deprecated `shouldInterceptRequest` must be used until minimum API >= 21. @SuppressWarnings("deprecation") @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url){ - if (adBlockerEnabled) { // Block ads. - // Extract the host from `url`. - Uri requestUri = Uri.parse(url); - String requestHost = requestUri.getHost(); - - // Initialize a variable to track if this is an ad server. - boolean requestHostIsAdServer = false; - - // Check all the subdomains of `requestHost` if it is not `null` against the ad server database. - if (requestHost != null) { - while (requestHost.contains(".") && !requestHostIsAdServer) { // Stop checking if we run out of `.` or if we already know that `requestHostIsAdServer` is `true`. - if (adServersSet.contains(requestHost)) { - requestHostIsAdServer = true; + if (adBlockerEnabled) { // Check the block lists. + Log.i("BlockLists", "Begin check for " + url); + + Uri uri = Uri.parse(url); + String domain = uri.getHost(); + + for (String whiteListEntry : mainWhiteList) { + if (url.contains(whiteListEntry)) { + Log.i("BlockLists", "Request allowed by main white list: " + whiteListEntry + " | " + url); + + // `Return null` loads the requested resource. + return null; + } + } + + for (String[] whiteListEntry : multiEntryWhiteList) { + if (whiteListEntry.length == 2) { // There are two entries. + if (url.contains(whiteListEntry[0]) && url.contains(whiteListEntry[1])) { + Log.i("BlockLists", "Request allowed by multi entry white list: " + whiteListEntry[0] + " , " + whiteListEntry[1] + " | " + url); + + // `Return null` loads the requested resource. + return null; } + } else { // There are three entries. + if (url.contains(whiteListEntry[0]) && url.contains(whiteListEntry[1]) && url.contains(whiteListEntry[2])) { + Log.i("BlockLists", "Request allowed by multi entry white list: " + whiteListEntry[0] + " , " + whiteListEntry[1] + " , " + whiteListEntry[2] + " | " + url); + + // `Return null` loads the requested resource. + return null; + } + } + } + + for (String blockListEntry : mainBlockList) { + if (url.contains(blockListEntry)) { + Log.i("BlockLists", "Request blocked by main block list: " + blockListEntry + " | " + url); - // Strip out the lowest subdomain of `requestHost`. - requestHost = requestHost.substring(requestHost.indexOf(".") + 1); + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); } } - if (requestHostIsAdServer) { // It is an ad server. - // Return an empty `WebResourceResponse`. - return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); - } else { // It is not an ad server. - // `return null` loads the requested resource. - return null; + for (String blockListEntry : initialBlockList) { + if (url.startsWith(blockListEntry)) { + Log.i("BlockLists", "Request blocked by initial block list: " + blockListEntry + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } } + + for (String blockListEntry : finalBlockList) { + if (url.endsWith(blockListEntry)) { + Log.i("BlockLists", "Request blocked by final block list: " + blockListEntry + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String[] blockListEntry : multiEntryBlockList) { + if (blockListEntry.length == 2) { // There are two entries. + if (url.contains(blockListEntry[0]) && url.contains(blockListEntry[1])) { + Log.i("BlockLists", "Request blocked by multi entry block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } else { // There are three entries. + if (url.contains(blockListEntry[0]) && url.contains(blockListEntry[1]) && url.contains(blockListEntry[2])) { + Log.i("BlockLists", "Request blocked by multi entry block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " , " + blockListEntry[2] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + } + + for (String[] blockListEntry : multiEntryInitialBlockList) { + if (url.startsWith(blockListEntry[0]) && url.contains(blockListEntry[1])) { + Log.i("BlockLists", "Request blocked by multi entry initial block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String[] blockListEntry : multiEntryFinalBlockList) { + if (url.contains(blockListEntry[0]) && url.endsWith(blockListEntry[1])) { + Log.i("BlockLists", "Request blocked by multi entry final block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String[] blockListEntry : domainBlockList) { + if (domain.endsWith(blockListEntry[0]) && url.contains(blockListEntry[1])) { + Log.i("BlockLists", "Request blocked by domain block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String[] blockListEntry : domainInitialBlockList) { + if (domain.endsWith(blockListEntry[0]) && url.startsWith(blockListEntry[1])) { + Log.i("BlockLists", "Request blocked by domain initial block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String[] blockListEntry : domainFinalBlockList) { + if (domain.endsWith(blockListEntry[0]) && url.endsWith(blockListEntry[2])) { + Log.i("BlockLists", "Request blocked by domain final block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String[] blockListEntry : domainMultiEntryBlockList) { + if (domain.endsWith(blockListEntry[0]) && url.contains(blockListEntry[1]) && url.contains(blockListEntry[2])) { + Log.i("BlockLists", "Request blocked by domain multi entry block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " , " + blockListEntry[2] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String[] blockListEntry : domainRegularExpressionBlockList) { + if (domain.endsWith(blockListEntry[0]) && Pattern.matches(blockListEntry[1], url)) { + Log.i("BlockLists", "Request blocked by domain regular expression block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + for (String blockListEntry : regularExpressionBlockList) { + if (Pattern.matches(blockListEntry, url)) { + Log.i("BlockLists", "Request blocked by regular expression block list: " + blockListEntry + " | " + url); + + // Return an empty `WebResourceResponse`. + return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); + } + } + + Log.i("BlockLists", "End check for " + url); + + // `return null` loads the requested resource. + return null; } else { // Ad blocking is disabled. // `return null` loads the requested resource. return null; @@ -1077,9 +1906,11 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD } // Check to see if the pinned SSL certificate matches the current website certificate. - if (!currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) || !currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) || !currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) || - !currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) || !currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) || !currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) || - !currentWebsiteSslStartDateString.equals(pinnedDomainSslStartDateString) || !currentWebsiteSslEndDateString.equals(pinnedDomainSslEndDateString)) { // The pinned SSL certificate doesn't match the current domain certificate. + if (!currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) || !currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) || + !currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) || !currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) || + !currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) || !currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) || + !currentWebsiteSslStartDateString.equals(pinnedDomainSslStartDateString) || !currentWebsiteSslEndDateString.equals(pinnedDomainSslEndDateString)) { + // The pinned SSL certificate doesn't match the current domain certificate. //Display the pinned SSL certificate mismatch `AlertDialog`. AppCompatDialogFragment pinnedSslCertificateMismatchDialogFragment = new PinnedSslCertificateMismatchDialog(); pinnedSslCertificateMismatchDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_mismatch)); @@ -1106,9 +1937,11 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Proceed to the website if the current SSL website certificate matches the pinned domain certificate. if (pinnedDomainSslCertificate && - currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) && currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) && currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) && - currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) && currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) && currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) && - currentWebsiteSslStartDate.equals(pinnedDomainSslStartDate) && currentWebsiteSslEndDate.equals(pinnedDomainSslEndDate)) { // An SSL certificate is pinned and matches the current domain certificate. + currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) && currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) && + currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) && currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) && + currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) && currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) && + currentWebsiteSslStartDate.equals(pinnedDomainSslStartDate) && currentWebsiteSslEndDate.equals(pinnedDomainSslEndDate)) { + // An SSL certificate is pinned and matches the current domain certificate. // Proceed to the website without displaying an error. handler.proceed(); } else { // Either there isn't a pinned SSL certificate or it doesn't match the current website certificate. @@ -1131,13 +1964,13 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD public void onProgressChanged(WebView view, int progress) { // Inject the night mode CSS if night mode is enabled. if (nightMode) { - // `background-color: #212121` sets the background to be dark gray. `color: #BDBDBD` sets the text color to be light gray. `box-shadow: none` removes a lower underline on links used by WordPress. - // `text-decoration: none` removes all text underlines. `text-shadow: none` removes text shadows, which usually have a hard coded color. `border: none` removes all borders, which can also be used to underline text. + // `background-color: #212121` sets the background to be dark gray. `color: #BDBDBD` sets the text color to be light gray. `box-shadow: none` removes a lower underline on links + // used by WordPress. `text-decoration: none` removes all text underlines. `text-shadow: none` removes text shadows, which usually have a hard coded color. + // `border: none` removes all borders, which can also be used to underline text. // `a {color: #1565C0}` sets links to be a dark blue. `!important` takes precedent over any existing sub-settings. - mainWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = '" + - "* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important; text-shadow: none !important; border: none !important;}" + - "a {color: #1565C0 !important;}" + - "'; parent.appendChild(style)})()", value -> { + mainWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; " + + "style.innerHTML = '* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important;" + + "text-shadow: none !important; border: none !important;} a {color: #1565C0 !important;}'; parent.appendChild(style)})()", value -> { // Initialize a `Handler` to display `mainWebView`. Handler displayWebViewHandler = new Handler(); @@ -1166,7 +1999,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD progressBar.setVisibility(View.GONE); // Display `mainWebView` if night mode is disabled. - // Because of a race condition between `applyDomainSettings` and `onPageStarted`, when night mode is set by domain settings the `WebView` may be hidden even if night mode is not currently enabled. + // Because of a race condition between `applyDomainSettings` and `onPageStarted`, when night mode is set by domain settings the `WebView` may be hidden even if night mode is not + // currently enabled. if (!nightMode) { mainWebView.setVisibility(View.VISIBLE); } @@ -1296,7 +2130,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD privacyBrowserRuntime = Runtime.getRuntime(); // Store the application's private data directory. - privateDataDirectoryString = getApplicationInfo().dataDir; // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`. + privateDataDirectoryString = getApplicationInfo().dataDir; + // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`. // Initialize `inFullScreenBrowsingMode`, which is always false at this point because Privacy Browser never starts in full screen browsing mode. inFullScreenBrowsingMode = false; @@ -1315,9 +2150,10 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Initialize `webViewTitle`. webViewTitle = getString(R.string.no_title); - // Initialize `favoriteIconBitmap`. We have to use `ContextCompat` until API >= 21. + // Initialize `favoriteIconBitmap`. `ContextCompat` must be used until API >= 21. Drawable favoriteIconDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.world); BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable; + assert favoriteIconBitmapDrawable != null; favoriteIconDefaultBitmap = favoriteIconBitmapDrawable.getBitmap(); // If the favorite icon is null, load the default. @@ -1922,7 +2758,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Show the Find on Page `RelativeLayout`. findOnPageLinearLayout.setVisibility(View.VISIBLE); - // Display the keyboard. We have to wait 200 ms before running the command to work around a bug in Android. http://stackoverflow.com/questions/5520085/android-show-softkeyboard-with-showsoftinput-is-not-working + // Display the keyboard. We have to wait 200 ms before running the command to work around a bug in Android. + // http://stackoverflow.com/questions/5520085/android-show-softkeyboard-with-showsoftinput-is-not-working findOnPageEditText.postDelayed(() -> { // Set the focus on `findOnPageEditText`. findOnPageEditText.requestFocus(); @@ -2122,8 +2959,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD try { // Delete the main cache directory. privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache"); - - // Delete the secondary `Service Worker` cache directory. We have to use a `String[]` because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise. + // Delete the secondary `Service Worker` cache directory. + // We have to use a `String[]` because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise. privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"}); } catch (IOException e) { // Do nothing if an error is thrown. @@ -2196,7 +3033,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD adView = findViewById(R.id.adview); } - // `invalidateOptionsMenu` should recalculate the number of action buttons from the menu to display on the app bar, but it doesn't because of the this bug: https://code.google.com/p/android/issues/detail?id=20493#c8 + // `invalidateOptionsMenu` should recalculate the number of action buttons from the menu to display on the app bar, but it doesn't because of the this bug: + // https://code.google.com/p/android/issues/detail?id=20493#c8 // ActivityCompat.invalidateOptionsMenu(this); } @@ -3185,7 +4023,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD cookieManager.setAcceptThirdPartyCookies(mainWebView, thirdPartyCookiesEnabled); } - // Only set the user agent if the webpage is not currently loading. Otherwise, changing the user agent on redirects can cause the original website to reload. <https://redmine.stoutner.com/issues/160> + // Only set the user agent if the webpage is not currently loading. Otherwise, changing the user agent on redirects can cause the original website to reload. + // <https://redmine.stoutner.com/issues/160> if (!urlIsLoading) { switch (userAgentString) { case "System default user agent": @@ -3264,7 +4103,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD cookieManager.setAcceptThirdPartyCookies(mainWebView, thirdPartyCookiesEnabled); } - // Only set the user agent if the webpage is not currently loading. Otherwise, changing the user agent on redirects can cause the original website to reload. <https://redmine.stoutner.com/issues/160> + // Only set the user agent if the webpage is not currently loading. Otherwise, changing the user agent on redirects can cause the original website to reload. + // <https://redmine.stoutner.com/issues/160> if (!urlIsLoading) { switch (defaultUserAgentString) { case "WebView default user agent": @@ -3381,9 +4221,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD } } - // `invalidateOptionsMenu` calls `onPrepareOptionsMenu()` and redraws the icons in the `AppBar`. `this` references the current activity. + // `invalidateOptionsMenu` calls `onPrepareOptionsMenu()` and redraws the icons in the `AppBar`. if (runInvalidateOptionsMenu) { - ActivityCompat.invalidateOptionsMenu(this); + invalidateOptionsMenu(); } } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 5e9f791b..a8ce68ca 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>. + Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>. Translation 2016 Aaron Gerlach <aaron@gerlach.com>. Copyright assigned to Soren Stoutner <soren@stoutner.com>. @@ -27,7 +27,8 @@ <!-- Activities. --> <string name="privacy_browser">Privacy Browser</string> <string name="privacy_browser_settings">Privacy Browser Einstellungen</string> - <string name="android_asset_path">de</string> <!-- For translations, this should be the localization abbreviation. --> + <!-- For translations, `android_asset_path` should be the localization abbreviation. For example, Spanish is `es`. This should not be translated unless the Guide and About sections are localized. --> + <string name="android_asset_path">de</string> <!-- MainWebView. --> <string name="privacy_mode">Privatsphäre-Modus</string> diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 89a088d8..2b5964ec 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -24,7 +24,8 @@ <!-- Activities. --> <string name="privacy_browser">Navegador Privado</string> <string name="privacy_browser_settings">Configuración de Navegador Privado</string> - <string name="android_asset_path">es</string> <!-- For translations, this should be the localization abbreviation. --> + <!-- For translations, `android_asset_path` should be the localization abbreviation. For example, Spanish is `es`. This should not be translated unless the Guide and About sections are localized. --> + <string name="android_asset_path">es</string> <!-- MainWebViewActivity. --> <string name="privacy_mode">Modo Privado</string> diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 7184b0a6..59a5b907 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -24,7 +24,8 @@ <!-- Activities. --> <string name="privacy_browser">Privacy Browser</string> <string name="privacy_browser_settings">Impostazioni</string> - <string name="android_asset_path">it</string> <!-- For translations, this should be the localization abbreviation. --> + <!-- For translations, `android_asset_path` should be the localization abbreviation. For example, Spanish is `es`. This should not be translated unless the Guide and About sections are localized. --> + <string name="android_asset_path">it</string> <!-- MainWebView. --> <string name="privacy_mode">Modalità privata</string> @@ -141,7 +142,7 @@ <string name="find_on_page">Cerca nella pagina</string> <string name="print">Stampa</string> <string name="privacy_browser_web_page">Pagina web di Privacy Browser</string> - <string name="view_source">Visualizza Sorgente</string> + <string name="view_source">Visualizza sorgente</string> <string name="add_to_home_screen">Aggiungi collegamento</string> <string name="refresh">Aggiorna</string> @@ -160,10 +161,10 @@ <!-- View Source. --> <string name="request_headers">Richiesta Intestazioni</string> - <string name="response_message">Messaggio di risposta</string> + <string name="response_message">Messaggio di Risposta</string> <string name="response_headers">Risposta Intestazioni</string> - <string name="response_body">Testo della risposta</string> - <string name="error_body">Testo errore</string> + <string name="response_body">Testo della Risposta</string> + <string name="error_body">Testo Errore</string> <string name="about_view_source">Informazioni sulla visualizzazione della sorgente</string> <string name="about_view_source_message">Dal momento che la WebView di Android non fornisce indicazioni sulla sorgente è stata effettuata una richiesta separata utilizzando i system tools in modo da ottenere le informazioni mostrate. Potrebbero esserci alcune differenze tra questi dati e quelli utilizzati da WebView. Questa limitazione sarà eliminata nella serie 4.x quando verrà rilasciata Privacy WebView.</string> diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml new file mode 100644 index 00000000..04ce5ee7 --- /dev/null +++ b/app/src/main/res/values-ru/strings.xml @@ -0,0 +1,417 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Copyright © 2015-2018 Soren Stoutner <soren@stoutner.com>. + + ÐÑÐ¾Ñ Ñайл ÑвлÑеÑÑÑ ÑаÑÑÑÑ Privacy Browser <https://www.stoutner.com/privacy-browser>. + + Privacy Browser ÑвлÑеÑÑÑ ÑвободнÑм пÑогÑаммнÑм обеÑпеÑением: Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе ÑаÑпÑоÑÑÑанÑÑÑ + его и/или модиÑиÑиÑоваÑÑ ÐµÐ³Ð¾ на ÑÑловиÑÑ Ð¿ÑблиÑной лиÑензии GNU, + опÑбликованной Фондом Ñвободного пÑогÑаммного обеÑпеÑениÑ, либо + ÑÑеÑÑей веÑÑии лиÑензии, либо (по ваÑÐµÐ¼Ñ Ð²ÑбоÑÑ) лÑбой более поздней веÑÑии. + + Privacy Browser ÑаÑпÑоÑÑÑанÑеÑÑÑ Ð² надежде, ÑÑо он бÑÐ´ÐµÑ Ð¿Ð¾Ð»ÐµÐ·ÐµÐ½, + но ÐÐÐ ÐÐÐÐÐ¥-ÐÐÐÐ ÐÐÐ ÐÐТÐÐ; даже без подÑазÑмеваемой гаÑанÑии пÑигодноÑÑи + Ð ÐÐÐÐÐРЧÐСÐÐÐ ÐÐЯТÐÐЬÐÐСТРÐÐÐ ÐÐЯ ÐÐÐ ÐÐÐÐÐÐÐÐРЦÐÐÐ. Ðолее подÑобнÑÑ + инÑоÑмаÑÐ¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ полÑÑиÑÑ Ð¾Ð·Ð½Ð°ÐºÐ¾Ð¼Ð¸Ð²ÑиÑÑ Ñ ÑÑловиÑми пÑблиÑной лиÑензии GNU. + + ÐÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±Ñли полÑÑиÑÑ ÐºÐ¾Ð¿Ð¸Ñ Ð¿ÑблиÑной лиÑензии GNU вмеÑÑе Ñ + Privacy Browser. ÐÑли неÑ, поÑеÑиÑе <http://www.gnu.org/licenses/>. --> + +<!-- `tools:ignore="MissingTranslation"` allows release APKs to be built if translation strings are missing. The missing strings will fall back to English. --> +<resources + xmlns:tools="http://schemas.android.com/tools" + tools:ignore="MissingTranslation" > + + <!-- Activities. --> + <string name="privacy_browser">Privacy Browser</string> + <string name="privacy_browser_settings">ÐаÑÑÑойки Privacy Browser</string> + <!-- For translations, `android_asset_path` should be the localization abbreviation. For example, Spanish is `es`. This should not be translated unless the Guide and About sections are localized. --> + <!-- <string name="android_asset_path">ru</string> --> + + <!-- MainWebView. --> + <string name="privacy_mode">Режим пÑиваÑноÑÑи</string> + <string name="javascript_enabled">JavaScript вклÑÑен</string> + <string name="javascript_disabled">JavaScript оÑклÑÑен</string> + <string name="first_party_cookies_enabled">ÐеÑвиÑнÑе ÑÐ°Ð¹Ð»Ñ cookie вклÑÑенÑ</string> + <string name="first_party_cookies_disabled">ÐеÑвиÑнÑе ÑÐ°Ð¹Ð»Ñ cookie оÑклÑÑенÑ</string> + <string name="third_party_cookies_enabled">СÑоÑонние ÑÐ°Ð¹Ð»Ñ cookie вклÑÑенÑ</string> + <string name="third_party_cookies_disabled">СÑоÑонние ÑÐ°Ð¹Ð»Ñ cookie оÑклÑÑенÑ</string> + <string name="dom_storage_enabled">Ð¥ÑанилиÑе DOM вклÑÑено</string> + <string name="dom_storage_disabled">Ð¥ÑанилиÑе DOM оÑклÑÑено</string> + <string name="form_data_enabled">ÐаннÑе ÑоÑÐ¼Ñ Ð²ÐºÐ»ÑÑенÑ</string> + <string name="form_data_disabled">ÐаннÑе ÑоÑÐ¼Ñ Ð¾ÑклÑÑенÑ</string> + <string name="cookies_deleted">Ð¤Ð°Ð¹Ð»Ñ cookie ÑдаленÑ</string> + <string name="dom_storage_deleted">Ð¥ÑанилиÑе DOM Ñдалено</string> + <string name="form_data_deleted">ÐаннÑе ÑоÑÐ¼Ñ ÑдаленÑ</string> + <string name="open_navigation_drawer">ÐÑкÑÑÑÑ Ð¿Ð°Ð½ÐµÐ»Ñ Ð½Ð°Ð²Ð¸Ð³Ð°Ñии</string> + <string name="close_navigation_drawer">ÐакÑÑÑÑ Ð¿Ð°Ð½ÐµÐ»Ñ Ð½Ð°Ð²Ð¸Ð³Ð°Ñии</string> + <string name="no_title">Ðез названиÑ</string> + + <!-- Save As. --> + <string name="save_as">Ð¡Ð¾Ñ ÑаниÑÑ ÐºÐ°Ðº</string> + <string name="save_image_as">Ð¡Ð¾Ñ ÑаниÑÑ Ð¸Ð·Ð¾Ð±Ñажение как</string> + <string name="file_name">ÐÐ¼Ñ Ñайла</string> + <string name="image_name">Ðазвание изобÑажениÑ</string> + <string name="unknown_size">неизвеÑÑнÑй ÑазмеÑ</string> + <string name="download">СкаÑаÑÑ</string> + <string name="cannot_download_file">Ðевозможно загÑÑзиÑÑ ÑÑÐ¾Ñ Ñайл, поÑколÑÐºÑ Ð¾Ð½ не ÑодеÑÐ¶Ð¸Ñ Ð¸Ð´ÐµÐ½ÑиÑикаÑÐ¾Ñ ÑеÑÑÑÑа HTTP или HTTPS.</string> + <string name="cannot_download_image">Ðевозможно загÑÑзиÑÑ ÑÑо изобÑажение, поÑколÑÐºÑ Ð¾Ð½Ð¾ не ÑодеÑÐ¶Ð¸Ñ Ð¸Ð´ÐµÐ½ÑиÑикаÑÐ¾Ñ ÑеÑÑÑÑа HTTP или HTTPS.</string> + + <!-- Custom App Bar. --> + <string name="favorite_icon">ÐнаÑок ÑайÑа</string> + <string name="url_or_search_terms">URL или поиÑковÑй запÑоÑ</string> + + <!-- View SSL Certificate. --> + <string name="view_ssl_certificate">ÐÑоÑмоÑÑ ÑеÑÑиÑикаÑа SSL</string> + <string name="unencrypted_website">ÐезаÑиÑÑованнÑй веб-ÑайÑ</string> + <string name="no_ssl_certificate">СвÑÐ·Ñ Ñ ÑÑим ÑайÑом не ÑиÑÑÑеÑÑÑ. ÐÑо позволÑÐµÑ ÑÑеÑÑим ÑÑоÑонам пеÑÐµÑ Ð²Ð°ÑÑваÑÑ Ð¸Ð½ÑоÑмаÑиÑ, оÑÑлеживаÑÑ Ð¿ÑоÑмоÑÑ Ð¸ вводиÑÑ Ð²ÑедоноÑнÑй конÑенÑ.</string> + <string name="ssl_certificate">СеÑÑиÑÐ¸ÐºÐ°Ñ SSL</string> + <string name="close">ÐакÑÑÑÑ</string> + <string name="domain">Ðомен</string> + <string name="domain_label">Ðомен:</string> + <string name="issued_to">ÐÑдан</string> + <string name="issued_by">Ðем вÑдан</string> + <string name="common_name">ÐбÑепÑинÑÑое Ð¸Ð¼Ñ (CN):</string> + <string name="organization">ÐÑганизаÑÐ¸Ñ (O):</string> + <string name="organizational_unit">ÐодÑазделение (OU):</string> + <string name="valid_dates">СÑок дейÑÑвиÑ</string> + <string name="start_date">ÐаÑало:</string> + <string name="end_date">ÐонеÑ:</string> + + <!-- SSL Certificate Error. --> + <string name="ssl_certificate_error">ÐÑибка ÑеÑÑиÑикаÑа SSL</string> + <string name="proceed">ÐÑодолжиÑÑ</string> + <string name="future_certificate">ÐаÑа наÑала дейÑÑÐ²Ð¸Ñ ÑеÑÑиÑикаÑа еÑе не наÑÑÑпила</string> + <string name="expired_certificate">СÑок дейÑÑÐ²Ð¸Ñ ÑеÑÑиÑикаÑа иÑÑек</string> + <string name="cn_mismatch">ÐбÑепÑинÑÑое Ð¸Ð¼Ñ Ð½Ðµ ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ Ñ Ð¾ÑÑа</string> + <string name="untrusted">ЦенÑÑ ÑеÑÑиÑикаÑии не ÑвлÑеÑÑÑ Ð´Ð¾Ð²ÐµÑеннÑм</string> + <string name="invalid_date">ÐедопÑÑÑÐ¸Ð¼Ð°Ñ Ð´Ð°Ñа ÑеÑÑиÑикаÑа</string> + <string name="invalid_certificate">ÐедопÑÑÑимÑй ÑеÑÑиÑикаÑ.</string> + <string name="url">URL</string> + <string name="url_label">URL:</string> + + <!-- Pinned SSL Certificate Mismatch. --> + <string name="update_ssl">Ðбновление SSL</string> + <string name="ssl_certificate_mismatch">ÐеÑооÑвеÑÑÑвие ÑеÑÑиÑикаÑа SSL</string> + <string name="current_ssl">ТекÑÑий SSL</string> + <string name="pinned_ssl">ÐакÑепленнÑй SSL</string> + + <!-- HTTP Authentication. --> + <string name="http_authentication">ÐÑÑенÑиÑикаÑÐ¸Ñ HTTP</string> + <string name="host">Host:</string> + <string name="username">ÐÐ¼Ñ Ð¿Ð¾Ð»ÑзоваÑелÑ</string> + <string name="password">ÐаÑолÑ</string> + + <!-- MainWebViewActivity Navigation Drawer. --> + <string name="navigation_drawer">ÐавигаÑÐ¸Ð¾Ð½Ð½Ð°Ñ Ð¿Ð°Ð½ÐµÐ»Ñ</string> + <string name="navigation">ÐавигаÑиÑ</string> + <string name="home">Ðомой</string> + <string name="back">Ðазад</string> + <string name="forward">ÐпеÑед</string> + <string name="history">ÐÑÑоÑиÑ</string> + <string name="clear_history">ÐÑиÑÑиÑÑ Ð¸ÑÑоÑиÑ</string> + <string name="bookmarks">Ðакладки</string> + <string name="downloads">ÐагÑÑзки</string> + <string name="settings">ÐаÑÑÑойки</string> + <string name="guide">Ð ÑководÑÑво</string> + <string name="about">Ð Privacy Browser</string> + <string name="clear_and_exit">ÐÑиÑÑиÑÑ Ð¸ вÑйÑи</string> + + <!-- MainWebViewActivity Options Menu. --> + <string name="javascript">JavaScript</string> + <string name="add_domain_settings">Ðобавление паÑамеÑÑов домена</string> + <string name="edit_domain_settings">Ðзменение паÑамеÑÑов домена</string> + <string name="first_party_cookies">ÐеÑвиÑнÑе ÑÐ°Ð¹Ð»Ñ cookie</string> + <string name="third_party_cookies">СÑоÑонние ÑÐ°Ð¹Ð»Ñ cookie</string> + <string name="dom_storage">Ð¥ÑанилиÑе DOM</string> + <string name="form_data">ÐаннÑе ÑоÑмÑ</string> + <string name="clear_data">ÐÑиÑÑиÑÑ Ð´Ð°Ð½Ð½Ñе</string> + <string name="clear_cookies">ÐÑиÑÑиÑÑ cookie</string> + <string name="clear_dom_storage"> ÐÑиÑÑиÑÑ Ñ ÑанилиÑе DOM</string> + <string name="clear_form_data">ÐÑиÑÑиÑÑ Ð´Ð°Ð½Ð½Ñе ÑоÑмÑ</string> + <string name="font_size">Ð Ð°Ð·Ð¼ÐµÑ ÑÑиÑÑа</string> + <string name="twenty_five_percent">25%</string> + <string name="fifty_percent">50%</string> + <string name="seventy_five_percent">75%</string> + <string name="one_hundred_percent">100%</string> + <string name="one_hundred_twenty_five_percent">125%</string> + <string name="one_hundred_fifty_percent">150%</string> + <string name="one_hundred_seventy_five_percent">175%</string> + <string name="two_hundred_percent">200%</string> + <string name="display_images">ÐоказÑваÑÑ Ð¸Ð·Ð¾Ð±ÑажениÑ</string> + <string name="share">ÐоделиÑÑÑÑ</string> + <string name="find_on_page">ÐайÑи на ÑÑÑаниÑе</string> + <string name="print">ÐеÑаÑÑ</string> + <string name="privacy_browser_web_page">Privacy Browser веб-ÑÑÑаниÑа</string> + <string name="view_source">ÐоÑмоÑÑеÑÑ Ð¸ÑÑоÑник</string> + <string name="add_to_home_screen">ÐобавиÑÑ Ð½Ð° домаÑний ÑкÑан</string> + <string name="refresh">ÐбновиÑÑ</string> + + <!-- Context Menus. --> + <string name="load_url">ÐагÑÑзиÑÑ URL</string> + <string name="copy_url">ÐопиÑоваÑÑ URL</string> + <string name="email_address">ÐдÑÐµÑ email</string> + <string name="copy_email_address">ÐопиÑоваÑÑ Ð°Ð´ÑÐµÑ email</string> + <string name="write_email">ÐапиÑаÑÑ email</string> + <string name="view_image">ÐÑоÑмоÑÑ Ð¸Ð·Ð¾Ð±ÑажениÑ</string> + <string name="download_image">СкаÑаÑÑ Ð¸Ð·Ð¾Ð±Ñажение</string> + + <!-- Find on Page. --> + <string name="previous">ÐÑедÑдÑÑий</string> + <string name="next">СледÑÑÑий</string> + + <!-- View Source. --> + <string name="request_headers">ÐапÑоÑиÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¸</string> + <string name="response_message">ÐÑвеÑное ÑообÑение</string> + <string name="response_headers">Ðаголовки оÑвеÑов</string> + <string name="response_body">Тело оÑвеÑа</string> + <string name="error_body">Тело оÑибки</string> + <string name="about_view_source">Ðб иÑÑоÑнике пÑедÑÑавлениÑ</string> + <string name="about_view_source_message">ÐоÑколÑÐºÑ Android WebView не пÑедоÑÑавлÑÐµÑ Ð¸ÑÑ Ð¾Ð´Ð½Ñе даннÑе, Ð´Ð»Ñ ÑбоÑа инÑоÑмаÑии, оÑобÑажаемой в ÑÑом дейÑÑвии, + бÑл Ñделан оÑделÑнÑй запÑÐ¾Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑиÑÑемнÑÑ ÑÑедÑÑв. ÐÐµÐ¶Ð´Ñ ÑÑими даннÑми и Ñеми, коÑоÑÑе иÑполÑзÑÑÑÑÑ Ð² WebView, могÑÑ Ð±ÑÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе оÑлиÑиÑ. + ÐÑо огÑаниÑение бÑÐ´ÐµÑ Ñдалено в ÑеÑии 4.x Ñ Ð²ÑпÑÑком Privacy WebView.</string> + + <!-- Create Home Screen Shortcut Alert Dialog. --> + <string name="create_shortcut">СоздаÑÑ ÑÑлÑк</string> + <string name="shortcut_name">ÐÐ¼Ñ ÑÑлÑка</string> + <string name="cancel">ÐÑмена</string> + <string name="create">СоздаÑÑ</string> + + <!-- Bookmarks. --> + <string name="database_view">ÐÑоÑмоÑÑ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ </string> + <string name="create_bookmark">СоздаÑÑ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÑ</string> + <string name="create_folder">СоздаÑÑ Ð¿Ð°Ð¿ÐºÑ</string> + <string name="current_bookmark_icon">ТекÑÑий знаÑок закладки</string> + <string name="current_folder_icon">ТекÑÑий знаÑок папки</string> + <string name="default_folder_icon">ÐнаÑок папки по ÑмолÑаниÑ</string> + <string name="web_page_favorite_icon">ÐнаÑок избÑанной веб-ÑÑÑаниÑÑ</string> + <string name="bookmark_name">ÐÐ¼Ñ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ¸</string> + <string name="folder_name">ÐÐ¼Ñ Ð¿Ð°Ð¿ÐºÐ¸</string> + <string name="bookmark_url">URL-адÑÐµÑ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ¸</string> + <string name="folder_names_must_be_unique">Ðмена папок Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑникалÑнÑми</string> + <string name="edit_bookmark">ÐзмениÑÑ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÑ</string> + <string name="edit_folder">ÐзмениÑÑ Ð¿Ð°Ð¿ÐºÑ</string> + <string name="move_to_folder">ÐеÑемеÑÑиÑÑ Ð² папкÑ</string> + <string name="move">ÐеÑемеÑÑиÑÑ</string> + <string name="save">Ð¡Ð¾Ñ ÑаниÑÑ</string> + + <!-- Bookmarks Contextual App Bar. --> + <string name="one_selected">1 вÑбÑана</string> + <string name="selected">вÑбÑанÑ</string> <!--This is a plural adjective.--> + <string name="move_up">ÐвеÑÑ </string> + <string name="move_down">Ðниз</string> + <string name="edit">ÐзмениÑÑ</string> + <string name="delete">УдалиÑÑ</string> + <string name="select_all">ÐÑбÑаÑÑ Ð²Ñе</string> + <string name="one_bookmark_deleted">1 закладка Ñдалена</string> + <string name="bookmarks_deleted">закладок ÑдаленÑ</string> + <string name="undo">ÐеÑнÑÑÑ</string> + + <!-- Bookmarks Database View. --> + <string name="bookmarks_database_view">ÐÑоÑмоÑÑ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ Ð·Ð°ÐºÐ»Ð°Ð´Ð¾Ðº</string> + <string name="all_folders">ÐÑе папки</string> + <string name="home_folder">ÐомаÑнÑÑ Ð¿Ð°Ð¿ÐºÐ°</string> + <string name="database_id">ID Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ :</string> + <string name="folder">Ðапка:</string> + <string name="parent_folder">РодиÑелÑÑÐºÐ°Ñ Ð¿Ð°Ð¿ÐºÐ°:</string> + <string name="display_order">ÐоÑÑдок оÑобÑажениÑ:</string> + + <!-- Domains. --> + <string name="domains">ÐоменÑ</string> + <string name="domain_settings">ÐаÑÑÑойки домена</string> + <string name="add_domain">ÐобавиÑÑ Ð´Ð¾Ð¼ÐµÐ½</string> + <string name="domain_name_already_exists">Ðоменное Ð¸Ð¼Ñ Ñже ÑÑÑеÑÑвÑеÑ</string> + <string name="add">ÐобавиÑÑ</string> + <string name="domain_name">ÐÐ¼Ñ Ð´Ð¾Ð¼ÐµÐ½Ð°</string> + <string name="domain_deleted">Ðомен Ñдален</string> + <string name="domain_name_instructions">добавÑÑе *. Ð´Ð»Ñ Ð²ÐºÐ»ÑÑÐµÐ½Ð¸Ñ Ð²ÑÐµÑ Ð¿Ð¾Ð´Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð² (напÑ. * .yandex.ru)</string> + <string-array name="display_webpage_images_array"> + <item>ÐаÑÑÑойки по ÑмолÑаниÑ</item> + <item>ÐзобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð²ÐºÐ»ÑÑенÑ</item> + <item>ÐзобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð²ÑклÑÑенÑ</item> + </string-array> + <string-array name="night_mode_array"> + <item>ÐаÑÑÑойки по ÑмолÑаниÑ</item> + <item>ÐоÑной Ñежим вклÑÑен</item> + <item>ÐоÑной Ñежим вÑклÑÑен</item> + </string-array> + <string name="pinned_ssl_certificate">ÐакÑепленнÑй ÑеÑÑиÑÐ¸ÐºÐ°Ñ SSL</string> + <string name="saved_ssl_certificate">Ð¡Ð¾Ñ ÑаненнÑй ÑеÑÑиÑÐ¸ÐºÐ°Ñ SSL</string> + <string name="current_website_ssl_certificate">ТекÑÑий ÑеÑÑиÑÐ¸ÐºÐ°Ñ SSL ÑайÑа</string> + <string name="load_an_encrypted_website">ÐÑкÑойÑе заÑиÑÑованнÑй ÑÐ°Ð¹Ñ Ð¿ÐµÑед наÑÑÑойкой домена, ÑÑÐ¾Ð±Ñ Ð·Ð°Ð¿Ð¾Ð»Ð½Ð¸ÑÑ ÑекÑÑий ÑеÑÑиÑÐ¸ÐºÐ°Ñ SSL веб-ÑайÑа.</string> + + <!-- Guide. --> + <string name="privacy_browser_guide">Ð ÑководÑÑво по Privacy Browser</string> + <string name="overview">ÐбзоÑ</string> + <string name="local_storage">ÐокалÑное Ñ ÑанилиÑе</string> + <string name="ssl_certificates">СеÑÑиÑикаÑÑ SSL</string> + <string name="tracking_ids">ÐденÑиÑикаÑоÑÑ Ð¾ÑÑлеживаниÑ</string> + + <!-- Preferences. --> + <string name="privacy">ÐонÑиденÑиалÑноÑÑÑ</string> + <string name="javascript_preference">ÐклÑÑиÑÑ JavaScript по ÑмолÑаниÑ</string> + <string name="javascript_preference_summary">JavaScript позволÑÐµÑ Ð²ÐµÐ±-ÑайÑам запÑÑкаÑÑ Ð¿ÑогÑÐ°Ð¼Ð¼Ñ (ÑкÑипÑÑ) на ÑÑÑÑойÑÑве.</string> + <string name="first_party_cookies_preference">ÐклÑÑиÑÑ Ð¿ÐµÑвиÑнÑе ÑÐ°Ð¹Ð»Ñ cookie по ÑмолÑаниÑ</string> + <string name="first_party_cookies_preference_summary">Ðа ÑÑÑÑойÑÑÐ²Ð°Ñ Ñ Ð²ÐµÑÑией Android ÑÑаÑÑе Lollipop (веÑÑÐ¸Ñ 5.0) ÑÑим паÑамеÑÑом Ñакже акÑивиÑÑÑÑÑÑ ÑÑоÑонние ÑÐ°Ð¹Ð»Ñ cookie.</string> + <string name="third_party_cookies_preference">ÐклÑÑиÑÑ ÑÑоÑонние ÑÐ°Ð¹Ð»Ñ cookie по ÑмолÑаниÑ</string> + <string name="third_party_cookies_summary">ÐÑÐ¾Ñ Ð¿Ð°ÑамеÑÑ ÑÑебÑÐµÑ Android Lollipop (веÑÑÐ¸Ñ 5.0) или вÑÑе. Ðн не дейÑÑвÑеÑ, еÑли ÑÑоÑонние ÑÐ°Ð¹Ð»Ñ cookie оÑклÑÑенÑ.</string> + <string name="dom_storage_preference">ÐклÑÑиÑÑ Ñ ÑанилиÑе DOM по ÑмолÑаниÑ</string> + <string name="dom_storage_preference_summary">ÐÐ»Ñ ÑабоÑÑ Ñ ÑанилиÑа DOM должен бÑÑÑ Ð²ÐºÐ»ÑÑен JavaScript.</string> + <string name="save_form_data_preference">РазÑеÑиÑÑ ÑÐ¾Ñ Ñанение даннÑÑ ÑоÑÐ¼Ñ Ð¿Ð¾ ÑмолÑаниÑ</string> + <string name="save_form_data_preference_summary">Ð¡Ð¾Ñ ÑаненнÑе даннÑе ÑоÑÐ¼Ñ Ð¼Ð¾Ð³ÑÑ Ð°Ð²ÑомаÑиÑеÑки заполнÑÑÑ Ð¿Ð¾Ð»Ñ Ð½Ð° веб-ÑайÑÐ°Ñ .</string> + <string name="user_agent">User agent</string> + <string-array name="user_agent_entries"> + <item>Privacy Browser 1.0</item> + <item>WebView по ÑмолÑаниÑ</item> + <item>Firefox 56 на Android 8.0.0</item> + <item>Chrome 62 на Android 8.0.0</item> + <item>Safari 11 на iOS 11.1</item> + <item>Firefox 52 на Linux</item> + <item>Chromium 61 на Linux</item> + <item>Firefox 56 на Windows 10</item> + <item>Chrome 62 на Windows 10</item> + <item>Edge 16 на Windows 10</item> + <item>Internet Explorer 11 на Windows 10</item> + <item>Safari 11.0.1 на macOS 10.13.1</item> + <item>ÐолÑзоваÑелÑÑкий</item> + </string-array> + <string-array name="domain_settings_user_agent_entries"> + <item>СиÑÑемнÑй по ÑмолÑаниÑ</item> + <item>Privacy Browser 1.0</item> + <item>WebView по ÑмолÑаниÑ</item> + <item>Firefox 56 на Android 8.0.0</item> + <item>Chrome 62 на Android 8.0.0</item> + <item>Safari 11 на iOS 11.1</item> + <item>Firefox 52 на Linux</item> + <item>Chromium 61 на Linux</item> + <item>Firefox 56 на Windows 10</item> + <item>Chrome 62 на Windows 10</item> + <item>Edge 16 на Windows 10</item> + <item>Internet Explorer 11 на Windows 10</item> + <item>Safari 11.0.1 на macOS 10.13.1</item> + <item>ÐолÑзоваÑелÑÑкий</item> + </string-array> + <string name="custom_user_agent">ÐолÑзоваÑелÑÑкий user agent</string> + <string name="block_ads">ÐлокиÑоваÑÑ ÑекламÑ</string> + <string name="block_ads_summary">ÐÐ»Ñ Ð±Ð»Ð¾ÐºÐ¸Ñовки ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸ÑполÑзоваÑÑ ÑпиÑок ÑеÑвеÑов pgl.yoyo.org.</string> + <string name="incognito_mode">Режим инкогниÑо</string> + <string name="incognito_mode_summary">ÐÑиÑÑка жÑÑнала и кÑÑа поÑле завеÑÑÐµÐ½Ð¸Ñ Ð·Ð°Ð³ÑÑзки каждой веб-ÑÑÑаниÑÑ.</string> + <string name="do_not_track">Ðе оÑÑлеживаÑÑ</string> + <string name="do_not_track_summary">ÐÑпÑавлÑÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº \'не оÑÑлеживаÑÑ\', ÑвлÑÑÑийÑÑ Ð¿Ð¾Ð¶ÐµÐ»Ð°Ð½Ð¸ÐµÐ¼ веб-ÑеÑвеÑÑ Ð½Ðµ оÑÑлеживаÑÑ ÑÑÐ¾Ñ Ð±ÑаÑзеÑ.</string> + <string name="tor">Tor</string> + <string name="proxy_through_orbot">ÐÑокÑи ÑеÑез Orbot</string> + <string name="proxy_through_orbot_summary">ÐÑокÑиÑоваÑÑ Ð²ÐµÑÑ Ð²ÐµÐ±-ÑÑаÑик ÑеÑез Orbot на localhost:8118.</string> + <string name="tor_homepage">ÐомаÑнÑÑ ÑÑÑаниÑа Tor</string> + <string name="tor_search">ÐоиÑк Tor</string> + <string-array name="tor_search_entries"> + <item>DuckDuckGo - JavaScript вÑклÑÑен</item> + <item>DuckDuckGo - JavaScript вклÑÑен</item> + <item>ÐолÑзоваÑелÑÑкий</item> + </string-array> + <string name="tor_search_custom_url">ÐолÑзоваÑелÑÑкий URL-адÑÐµÑ Ð¿Ð¾Ð¸Ñка Tor</string> + <string name="search">ÐоиÑк</string> + <string-array name="search_entries"> + <item>DuckDuckGo - JavaScript вÑклÑÑен</item> + <item>DuckDuckGo - JavaScript вклÑÑен</item> + <item>StartPage</item> + <item>Qwant - JavaScript вÑклÑÑен</item> + <item>Qwant - JavaScript вклÑÑен</item> + <item>Searx</item> + <item>Google</item> + <item>Bing</item> + <item>Yahoo - JavaScript вÑклÑÑен</item> + <item>Yahoo - JavaScript вклÑÑен</item> + <item>ÐолÑзоваÑелÑÑкий</item> + </string-array> + <string name="search_custom_url">ÐолÑзоваÑелÑÑкий URL-адÑÐµÑ Ð¿Ð¾Ð¸Ñка</string> + <string name="custom_url">ÐолÑзоваÑелÑÑкий URL-адÑеÑ</string> + <string name="full_screen">Ðо веÑÑ ÑкÑан</string> + <string name="full_screen_browsing_mode">ÐолноÑкÑаннÑй Ñежим пÑоÑмоÑÑа</string> + <string name="full_screen_browsing_mode_summary">Ðвойное нажаÑие пеÑеклÑÑÐ°ÐµÑ Ñежим пÑоÑмоÑÑа.</string> + <string name="hide_system_bars">СкÑÑÑÑ ÑиÑÑемнÑе панели</string> + <string name="hide_system_bars_summary">СкÑÑÑÑ Ð¿Ð°Ð½ÐµÐ»Ð¸ ÑÑаÑÑÑа и навигаÑии в полноÑкÑанном Ñежиме пÑоÑмоÑÑа. ÐÑо не ÑабоÑÐ°ÐµÑ Ð¿Ñи оÑобÑажении клавиаÑÑÑÑ Ð²Ð¾ вÑÐµÐ¼Ñ Ð¿Ð¾Ð»Ð½Ð¾ÑкÑанного пÑоÑмоÑÑа.</string> + <string name="translucent_navigation_bar">ÐолÑпÑозÑаÑÐ½Ð°Ñ Ð½Ð°Ð²Ð¸Ð³Ð°ÑÐ¸Ð¾Ð½Ð½Ð°Ñ Ð¿Ð°Ð½ÐµÐ»Ñ</string> + <string name="translucent_navigation_bar_summary">ÐÐ°Ð½ÐµÐ»Ñ Ð½Ð°Ð²Ð¸Ð³Ð°Ñии ÑÑÐ°Ð½ÐµÑ Ð¿Ð¾Ð»ÑпÑозÑаÑной в полноÑкÑанном Ñежиме пÑоÑмоÑÑа.</string> + <string name="clear_everything">ÐÑиÑÑиÑÑ Ð²Ñе</string> + <string name="clear_everything_summary">ÐÑиÑÐ°ÐµÑ ÑÐ°Ð¹Ð»Ñ cookie, Ñ ÑанилиÑе DOM, даннÑе ÑоÑÐ¼Ñ Ð¸ кÑÑ WebView. ÐаÑем вÑÑÑнÑÑ ÑдалÑÑÑÑÑ Ð²Ñе каÑалоги "app_webview" и "cache".</string> + <string name="clear_cookies_preference">ÐÑиÑÑиÑÑ ÑÐ°Ð¹Ð»Ñ cookie</string> + <string name="clear_cookies_summary">ÐÑиÑÑиÑÑ Ð¿ÐµÑвиÑнÑе и ÑÑоÑонние ÑÐ°Ð¹Ð»Ñ cookie.</string> + <string name="clear_dom_storage_preference">ÐÑиÑÑиÑÑ Ñ ÑанилиÑе DOM</string> + <string name="clear_dom_storage_summary">ÐÑиÑÐ°ÐµÑ Ñ ÑанилиÑе DOM.</string> + <string name="clear_form_data_preference">ÐÑиÑÑка даннÑÑ ÑоÑмÑ</string> + <string name="clear_form_data_summary">ÐÑиÑÐ°ÐµÑ Ð´Ð°Ð½Ð½Ñе ÑоÑмÑ.</string> + <string name="clear_cache">ÐÑиÑÑиÑÑ ÐºÑÑ</string> + <string name="clear_cache_summary">ÐÑиÑÐ°ÐµÑ ÐºÑÑ WebView.</string> + <string name="general">ÐбÑее</string> + <string name="homepage">ÐомаÑнÑÑ ÑÑÑаниÑа</string> + <string name="default_font_size">Ð Ð°Ð·Ð¼ÐµÑ ÑÑиÑÑа по ÑмолÑаниÑ</string> + <string-array name="default_font_size_entries"> + <item>25%</item> + <item>50%</item> + <item>75%</item> + <item>100%</item> + <item>125%</item> + <item>150%</item> + <item>175%</item> + <item>200%</item> + </string-array> + <string-array name="domain_settings_font_size_entries"> + <item>СиÑÑемнÑй по ÑмолÑаниÑ</item> + <item>25%</item> + <item>50%</item> + <item>75%</item> + <item>100%</item> + <item>125%</item> + <item>150%</item> + <item>175%</item> + <item>200%</item> + </string-array> + <string name="swipe_to_refresh_enabled">ÐоÑÑнÑÑÑ Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ</string> + <string name="swipe_to_refresh_enabled_summary">ÐекоÑоÑÑе веб-ÑайÑÑ Ð¼Ð¾Ð³ÑÑ ÑабоÑаÑÑ Ð½ÐµÐºÐ¾ÑÑекÑно пÑи вклÑÑении данной опÑии.</string> + <string name="display_additional_app_bar_icons">ÐÑобÑажаÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе знаÑки на панели пÑиложениÑ</string> + <string name="display_additional_app_bar_icons_summary">ÐÑобÑажение знаÑков Ð´Ð»Ñ Ð¿ÐµÑеклÑÑÐµÐ½Ð¸Ñ Ñайлов cookie, Ñ ÑанилиÑа DOM и даннÑÑ ÑоÑÐ¼Ñ Ð½Ð° панели пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñи налиÑии меÑÑа.</string> + <string name="dark_theme">Ð¢ÐµÐ¼Ð½Ð°Ñ Ñема</string> + <string name="dark_theme_summary">Ðзменение ÑÐµÐ¼Ñ Ð¿ÐµÑезапÑÑÐºÐ°ÐµÑ Privacy Browser.</string> + <string name="night_mode">ÐоÑной Ñежим</string> + <string name="night_mode_summary">ÐклÑÑение ноÑного Ñежима Ñакже вклÑÑÐ°ÐµÑ JavaScript Ð´Ð»Ñ Ð²ÑÐµÑ Ð²ÐµÐ±-ÑÑÑаниÑ.</string> + <string name="display_webpage_images">ÐоказÑваÑÑ Ð¸Ð·Ð¾Ð±ÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð²ÐµÐ±-ÑÑÑаниÑÑ</string> + <string name="display_webpage_images_summary">ÐÑклÑÑиÑе, Ð´Ð»Ñ Ñкономии ÑÑаÑика.</string> + + <!-- Orbot. --> + <string name="orbot_proxy_not_installed">ÐÑокÑиÑование Orbot ÑабоÑÐ°ÐµÑ ÑолÑко Ñ ÑÑÑановленнÑм Orbot.</string> + <string name="waiting_for_orbot">Ðжидание Orbot Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑÑениÑ...</string> + + <!-- About Activity. --> + <string name="about_privacy_browser">Ð Privacy Browser</string> + <string name="version">ÐеÑÑиÑ</string> + <string name="version_code">код веÑÑии</string> + <string name="hardware">ÐбоÑÑдование</string> + <string name="brand">ÐÑенд:</string> + <string name="manufacturer">ÐÑоизводиÑелÑ:</string> + <string name="model">ÐоделÑ:</string> + <string name="device">УÑÑÑойÑÑво:</string> + <string name="bootloader">ÐагÑÑзÑик:</string> + <string name="radio">Радио:</string> + <string name="software">ÐÑогÑаммное обеÑпеÑение</string> + <string name="android">Android:</string> + <string name="api">API</string> + <string name="build">СбоÑка:</string> + <string name="security_patch">ÐаÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑÑи:</string> + <string name="webkit">WebKit:</string> + <string name="chrome">Chrome:</string> + <string name="easylist">EasyList:</string> + <string name="orbot">Orbot:</string> + <string name="package_signature">ÐодпиÑÑ Ð¿Ð°ÐºÐµÑа</string> + <string name="issuer_dn">DN ÑмиÑенÑа:</string> + <string name="subject_dn">DN ÑÑбÑекÑа:</string> + <string name="certificate_version">ÐеÑÑÐ¸Ñ ÑеÑÑиÑикаÑа:</string> + <string name="serial_number">СеÑийнÑй номеÑ:</string> + <string name="signature_algorithm">ÐлгоÑиÑм подпиÑи:</string> + <string name="permissions">РазÑеÑениÑ</string> + <string name="privacy_policy">ÐолиÑика конÑиденÑиалÑноÑÑи</string> + <string name="changelog">ÐÑÑоÑÐ¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹</string> + <string name="licenses">ÐиÑензии</string> + <string name="contributors">ÐлагодаÑноÑÑи</string> + <string name="links">СÑÑлки</string> +</resources> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ac38ae34..4d1d3a65 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright © 2015-2017 Soren Stoutner <soren@stoutner.com>. + Copyright © 2015-2018 Soren Stoutner <soren@stoutner.com>. This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>. @@ -26,7 +26,8 @@ <!-- Activities. --> <string name="privacy_browser">Privacy Browser</string> <string name="privacy_browser_settings">Privacy Browser Settings</string> - <string name="android_asset_path">en</string> <!-- For translations, this should be the localization abbreviation. For example, Spanish is `es`. This should not be translated unless the Guide and About sections are localized. --> + <!-- For translations, `android_asset_path` should be the localization abbreviation. For example, Spanish is `es`. This should not be translated unless the Guide and About sections are localized. --> + <string name="android_asset_path">en</string> <!-- MainWebView. --> <string name="privacy_mode">Privacy Mode</string> @@ -321,7 +322,7 @@ <item>Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko</item> <item>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.4 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.4</item> <item>Custom user agent</item> <!-- This item must not be translated into other languages because it is referenced in code. It is never displayed on the screen. --> - </string-array> + </string-array> <string name="custom_user_agent">Custom user agent</string> <string name="block_ads">Block ads</string> <string name="block_ads_summary">Use the list of ad servers from pgl.yoyo.org to block ads.</string>