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;
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()`.
// `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()`.
// `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()`.
// 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);
+ }
+ }
}
}
// 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);
// 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);
}
// 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
}
}
- // 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;
}
// 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));
// 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.
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();
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);
}
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;
// 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.
// 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();
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.
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);
}
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":
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":
}
}
- // `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();
}
}
--- /dev/null
+<?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>