From fa3b8b382eb5ed86c598e3b126d1ef5dd117c5be Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Thu, 18 Apr 2019 12:44:53 -0700 Subject: [PATCH] Make SSL errors tab aware. --- .idea/codeStyles/Project.xml | 25 - .../dialogs/AdConsentDialog.java | 27 +- .../activities/AboutActivity.java | 65 +-- .../activities/BookmarksActivity.java | 73 ++- .../activities/MainWebViewActivity.java | 468 ++++++++---------- .../adapters/AboutPagerAdapter.java | 88 ++++ .../dialogs/AboutViewSourceDialog.java | 4 +- .../dialogs/HttpAuthenticationDialog.java | 122 +++-- .../dialogs/PinnedMismatchDialog.java | 4 +- .../dialogs/SslCertificateErrorDialog.java | 142 +++--- .../fragments/AboutTabFragment.java | 47 +- .../views/NestedScrollWebView.java | 81 ++- app/src/main/res/layout/main_framelayout.xml | 1 + .../main/res/layout/webview_framelayout.xml | 2 +- app/src/main/res/values-de/strings.xml | 8 + app/src/main/res/values-it/strings.xml | 7 + app/src/main/res/values-tr/strings.xml | 7 + app/src/main/res/values-v21/styles.xml | 18 +- app/src/main/res/values/attrs.xml | 1 + app/src/main/res/values/styles.xml | 18 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 22 files changed, 666 insertions(+), 548 deletions(-) create mode 100644 app/src/main/java/com/stoutner/privacybrowser/adapters/AboutPagerAdapter.java diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 92d6b7d5..86a569b8 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -33,31 +33,6 @@ - - - - - - - - - - diff --git a/app/src/free/java/com/stoutner/privacybrowser/dialogs/AdConsentDialog.java b/app/src/free/java/com/stoutner/privacybrowser/dialogs/AdConsentDialog.java index c0cf9721..bce865f2 100644 --- a/app/src/free/java/com/stoutner/privacybrowser/dialogs/AdConsentDialog.java +++ b/app/src/free/java/com/stoutner/privacybrowser/dialogs/AdConsentDialog.java @@ -22,14 +22,16 @@ package com.stoutner.privacybrowser.dialogs; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; +import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; +import android.preference.PreferenceManager; +import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; import com.stoutner.privacybrowser.R; -import com.stoutner.privacybrowser.activities.MainWebViewActivity; import com.stoutner.privacybrowser.helpers.AdConsentDatabaseHelper; import com.stoutner.privacybrowser.helpers.AdHelper; @@ -37,11 +39,18 @@ public class AdConsentDialog extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + // Get a handle for the shared preferences. + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + + // Get the screenshot and theme preferences. + boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false); + boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false); + // Use a builder to create the alert dialog. AlertDialog.Builder dialogBuilder; // Set the style and the icon according to the theme. - if (MainWebViewActivity.darkTheme) { + if (darkTheme) { dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark); dialogBuilder.setIcon(R.drawable.block_ads_enabled_dark); } else { @@ -87,8 +96,20 @@ public class AdConsentDialog extends DialogFragment { AdHelper.loadAd(getActivity().findViewById(R.id.adview), getActivity().getApplicationContext(), getString(R.string.ad_unit_id)); }); + // Create an alert dialog from the alert dialog builder. + AlertDialog alertDialog = dialogBuilder.create(); + + // Disable screenshots if not allowed. + if (!allowScreenshots) { + // Remove the warning below that `getWindow()` might be null. + assert alertDialog.getWindow() != null; + + // Disable screenshots. + alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + // Return the alert dialog. - return dialogBuilder.create(); + return alertDialog; } // Close Privacy Browser Free if the dialog is cancelled without selecting a button (by tapping on the background). diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/AboutActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/AboutActivity.java index e15bfe79..6ce5b431 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/AboutActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/AboutActivity.java @@ -19,6 +19,7 @@ package com.stoutner.privacybrowser.activities; +import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; @@ -27,14 +28,11 @@ import android.view.WindowManager; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; import com.google.android.material.tabs.TabLayout; -import com.stoutner.privacybrowser.fragments.AboutTabFragment; +import com.stoutner.privacybrowser.adapters.AboutPagerAdapter; import com.stoutner.privacybrowser.R; public class AboutActivity extends AppCompatActivity { @@ -62,6 +60,12 @@ public class AboutActivity extends AppCompatActivity { // Run the default commands. super.onCreate(savedInstanceState); + // Get the intent that launched the activity. + Intent launchingIntent = getIntent(); + + // Store the blocklist versions. + String[] blocklistVersions = launchingIntent.getStringArrayExtra("blocklist_versions"); + // Set the content view. setContentView(R.layout.about_coordinatorlayout); @@ -83,58 +87,9 @@ public class AboutActivity extends AppCompatActivity { actionBar.setDisplayHomeAsUpEnabled(true); // Setup the ViewPager. - aboutViewPager.setAdapter(new AboutPagerAdapter(getSupportFragmentManager())); + aboutViewPager.setAdapter(new AboutPagerAdapter(getSupportFragmentManager(), getApplicationContext(), blocklistVersions)); // Connect the tab layout to the view pager. aboutTabLayout.setupWithViewPager(aboutViewPager); } - - private class AboutPagerAdapter extends FragmentPagerAdapter { - private AboutPagerAdapter(FragmentManager fragmentManager) { - // Run the default commands. - super(fragmentManager); - } - - @Override - // Get the count of the number of tabs. - public int getCount() { - return 7; - } - - @Override - // Get the name of each tab. Tab numbers start at 0. - public CharSequence getPageTitle(int tab) { - switch (tab) { - case 0: - return getString(R.string.version); - - case 1: - return getString(R.string.permissions); - - case 2: - return getString(R.string.privacy_policy); - - case 3: - return getString(R.string.changelog); - - case 4: - return getString(R.string.licenses); - - case 5: - return getString(R.string.contributors); - - case 6: - return getString(R.string.links); - - default: - return ""; - } - } - - @Override - // Setup each tab. - public Fragment getItem(int tab) { - return AboutTabFragment.createTab(tab); - } - } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java index d29e54c4..12a96aee 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java @@ -478,50 +478,45 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma @SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`. @Override public void onDismissed(Snackbar snackbar, int event) { - switch (event) { - // The user pushed the `Undo` button. - case Snackbar.Callback.DISMISS_EVENT_ACTION: - // Update the bookmarks cursor with the current contents of the bookmarks database, including the "deleted" bookmarks. - bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); - - // Update the list view. - bookmarksCursorAdapter.changeCursor(bookmarksCursor); - - // Re-select the previously selected bookmarks. - for (int i = 0; i < selectedBookmarksPositionsSparseBooleanArray.size(); i++) { - bookmarksListView.setItemChecked(selectedBookmarksPositionsSparseBooleanArray.keyAt(i), true); - } - break; - - // The Snackbar was dismissed without the `Undo` button being pushed. - default: - // Delete each selected bookmark. - for (long databaseIdLong : selectedBookmarksIdsLongArray) { - // Convert `databaseIdLong` to an int. - int databaseIdInt = (int) databaseIdLong; - - // Delete the contents of the folder if the selected bookmark is a folder. - if (bookmarksDatabaseHelper.isFolder(databaseIdInt)) { - deleteBookmarkFolderContents(databaseIdInt); - } - - // Delete the selected bookmark. - bookmarksDatabaseHelper.deleteBookmark(databaseIdInt); + if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) { // The user pushed the undo button. + // Update the bookmarks cursor with the current contents of the bookmarks database, including the "deleted" bookmarks. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); + + // Update the list view. + bookmarksCursorAdapter.changeCursor(bookmarksCursor); + + // Re-select the previously selected bookmarks. + for (int i = 0; i < selectedBookmarksPositionsSparseBooleanArray.size(); i++) { + bookmarksListView.setItemChecked(selectedBookmarksPositionsSparseBooleanArray.keyAt(i), true); + } + } else { // The snackbar was dismissed without the undo button being pushed. + // Delete each selected bookmark. + for (long databaseIdLong : selectedBookmarksIdsLongArray) { + // Convert `databaseIdLong` to an int. + int databaseIdInt = (int) databaseIdLong; + + // Delete the contents of the folder if the selected bookmark is a folder. + if (bookmarksDatabaseHelper.isFolder(databaseIdInt)) { + deleteBookmarkFolderContents(databaseIdInt); } - // Update the display order. - for (int i = 0; i < bookmarksListView.getCount(); i++) { - // Get the database ID for the current bookmark. - int currentBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(i); + // Delete the selected bookmark. + bookmarksDatabaseHelper.deleteBookmark(databaseIdInt); + } + + // Update the display order. + for (int i = 0; i < bookmarksListView.getCount(); i++) { + // Get the database ID for the current bookmark. + int currentBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(i); - // Move `bookmarksCursor` to the current bookmark position. - bookmarksCursor.moveToPosition(i); + // Move `bookmarksCursor` to the current bookmark position. + bookmarksCursor.moveToPosition(i); - // Update the display order only if it is not correct in the database. - if (bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)) != i) { - bookmarksDatabaseHelper.updateDisplayOrder(currentBookmarkDatabaseId, i); - } + // Update the display order only if it is not correct in the database. + if (bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)) != i) { + bookmarksDatabaseHelper.updateDisplayOrder(currentBookmarkDatabaseId, i); } + } } // Reset the deleting bookmarks flag. 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 2be23411..4050a01f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -157,17 +157,19 @@ import java.util.Set; // TODO. Store up reloads for tabs that are not visible. // TODO. New tabs are white in dark mode. // TODO. Hide the tabs in full screen mode. +// TODO. Find on page. +// TODO. Use TabLayout.setScrollPosition to scroll to new tabs. // AppCompatActivity from android.support.v7.app.AppCompatActivity must be used to have access to the SupportActionBar until the minimum API is >= 21. public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener, - EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener, WebViewTabFragment.NewTabListener, - PinnedMismatchDialog.PinnedMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener { + EditBookmarkFolderDialog.EditBookmarkFolderListener, NavigationView.OnNavigationItemSelectedListener, WebViewTabFragment.NewTabListener, PinnedMismatchDialog.PinnedMismatchListener, + UrlHistoryDialog.UrlHistoryListener { // `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. public static String orbotStatus; - // The WebView pager adapter is accessed from `PinnedMismatchDialog`. It is also used in `onCreate()`, `onResume()`, and `addTab()`. + // The WebView pager adapter is accessed from `HttpAuthenticationDialog`, `PinnedMismatchDialog`, and `SslCertificateErrorDialog`. It is also used in `onCreate()`, `onResume()`, and `addTab()`. public static WebViewPagerAdapter webViewPagerAdapter; // `reloadOnRestart` is public static so it can be accessed from `SettingsFragment`. It is used in `onRestart()` @@ -180,13 +182,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `restartFromBookmarksActivity` is public static so it can be accessed from `BookmarksActivity`. It is also used in `onRestart()`. public static boolean restartFromBookmarksActivity; - // The blocklist versions are public static so they can be accessed from `AboutTabFragment`. They are also used in `onCreate()`. // TODO. - public static String easyListVersion; - public static String easyPrivacyVersion; - public static String fanboysAnnoyanceVersion; - public static String fanboysSocialVersion; - public static String ultraPrivacyVersion; - // `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; @@ -201,9 +196,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook - // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, `onSslMismatchBack()`, and `applyDomainSettings()`. - private boolean navigatingHistory; // TODO. - // The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxyThroughOrbot()`, and `applyDomainSettings()`. private NestedScrollWebView currentWebView; @@ -217,43 +209,30 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // The options menu is set in `onCreateOptionsMenu()` and used in `onOptionsItemSelected()`, `updatePrivacyIcons()`, and `initializeWebView()`. private Menu optionsMenu; - // TODO. This could probably be removed. - // The blocklist helper is used in `onCreate()` and `WebViewPagerAdapter`. - private BlockListHelper blockListHelper; - - // The blocklists are populated in `onCreate()` and accessed from `WebViewPagerAdapter`. + // The blocklists are populated in `onCreate()` and accessed from `initializeWebView()`. private ArrayList> easyList; private ArrayList> easyPrivacy; private ArrayList> fanboysAnnoyanceList; private ArrayList> fanboysSocialList; private ArrayList> ultraPrivacy; - // The blocklist menu items are used in `onCreateOptionsMenu()`, `onPrepareOptionsMenu()`, and `initializeWebView()`. // TODO. - private MenuItem blocklistsMenuItem; - private MenuItem easyListMenuItem; - private MenuItem easyPrivacyMenuItem; - private MenuItem fanboysAnnoyanceListMenuItem; - private MenuItem fanboysSocialBlockingListMenuItem; - private MenuItem ultraPrivacyMenuItem; - private MenuItem blockAllThirdPartyRequestsMenuItem; - // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`. private String webViewDefaultUserAgent; // `proxyThroughOrbot` is used in `onRestart()`, `onOptionsItemSelected()`, `applyAppSettings()`, and `applyProxyThroughOrbot()`. private boolean proxyThroughOrbot; - // `incognitoModeEnabled` is used in `onCreate()` and `applyAppSettings()`. - private boolean incognitoModeEnabled; // TODO. + // The incognito mode is set in `applyAppSettings()` and used in `initializeWebView()`. + private boolean incognitoModeEnabled; - // `fullScreenBrowsingModeEnabled` is used in `onCreate()` and `applyAppSettings()`. - private boolean fullScreenBrowsingModeEnabled; // TODO. + // The full screen browsing mode tracker is set it `applyAppSettings()` and used in `initializeWebView()`. + private boolean fullScreenBrowsingModeEnabled; // `inFullScreenBrowsingMode` is used in `onCreate()`, `onConfigurationChanged()`, and `applyAppSettings()`. private boolean inFullScreenBrowsingMode; - // Hide app bar is used in `onCreate()` and `applyAppSettings()`. - private boolean hideAppBar; // TODO. + // Hide app bar is used in `applyAppSettings()` and `initializeWebView()`. + private boolean hideAppBar; // `reapplyDomainSettingsOnRestart` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, and `onAddDomain()`, . private boolean reapplyDomainSettingsOnRestart; @@ -264,24 +243,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `displayingFullScreenVideo` is used in `onCreate()` and `onResume()`. private boolean displayingFullScreenVideo; - // `downloadWithExternalApp` is used in `onCreate()`, `onCreateContextMenu()`, and `applyDomainSettings()`. - private boolean downloadWithExternalApp; // TODO. - // `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`. private BroadcastReceiver orbotStatusBroadcastReceiver; // `waitingForOrbot` is used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. private boolean waitingForOrbot; - // `domainSettingsJavaScriptEnabled` is used in `onOptionsItemSelected()` and `applyDomainSettings()`. - private Boolean domainSettingsJavaScriptEnabled; // TODO. - - // `waitingForOrbotHtmlString` is used in `onCreate()` and `applyProxyThroughOrbot()`. - private String waitingForOrbotHtmlString; // TODO. - - // `privateDataDirectoryString` is used in `onCreate()`, `onOptionsItemSelected()`, and `onNavigationItemSelected()`. - private String privateDataDirectoryString; // TODO. - // The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`. private ActionBarDrawerToggle actionBarDrawerToggle; @@ -295,12 +262,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private int drawerHeaderPaddingTop; private int drawerHeaderPaddingBottom; - // `sslErrorHandler` is used in `onCreate()`, `onSslErrorCancel()`, and `onSslErrorProceed`. - private SslErrorHandler sslErrorHandler; // TODO. - - // `httpAuthHandler` is used in `onCreate()`, `onHttpAuthenticationCancel()`, and `onHttpAuthenticationProceed()`. - private static HttpAuthHandler httpAuthHandler; // TODO. - // `bookmarksDatabaseHelper` is used in `onCreate()`, `onDestroy`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, // and `loadBookmarksFolder()`. private BookmarksDatabaseHelper bookmarksDatabaseHelper; @@ -419,9 +380,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); - // Set `waitingForOrbotHTMLString`. - waitingForOrbotHtmlString = "

" + getString(R.string.waiting_for_orbot) + "

"; - // Initialize the Orbot status and the waiting for Orbot trackers. orbotStatus = "unknown"; waitingForOrbot = false; @@ -479,8 +437,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Register `orbotStatusBroadcastReceiver` on `this` context. this.registerReceiver(orbotStatusBroadcastReceiver, new IntentFilter("org.torproject.android.intent.action.STATUS")); - // Instantiate the block list helper. - blockListHelper = new BlockListHelper(); + // Instantiate the blocklist helper. + BlockListHelper blockListHelper = new BlockListHelper(); // Parse the block lists. easyList = blockListHelper.parseBlockList(getAssets(), "blocklists/easylist.txt"); @@ -489,13 +447,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook fanboysSocialList = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-social.txt"); ultraPrivacy = blockListHelper.parseBlockList(getAssets(), "blocklists/ultraprivacy.txt"); - // Store the list versions. - easyListVersion = easyList.get(0).get(0)[0]; - easyPrivacyVersion = easyPrivacy.get(0).get(0)[0]; - fanboysAnnoyanceVersion = fanboysAnnoyanceList.get(0).get(0)[0]; - fanboysSocialVersion = fanboysSocialList.get(0).get(0)[0]; - ultraPrivacyVersion = ultraPrivacy.get(0).get(0)[0]; - // Get handles for views that need to be modified. DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); NavigationView navigationView = findViewById(R.id.navigationview); @@ -824,13 +775,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Initialize the default preference values the first time the program is run. `false` keeps this command from resetting any current preferences back to default. PreferenceManager.setDefaultValues(this, R.xml.preferences, false); - // 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`. - - // Initialize `inFullScreenBrowsingMode`, which is always false at this point because Privacy Browser never starts in full screen browsing mode. - inFullScreenBrowsingMode = false; - // Inflate a bare WebView to get the default user agent. It is not used to render content on the screen. @SuppressLint("InflateParams") View webViewLayout = getLayoutInflater().inflate(R.layout.bare_webview, null, false); @@ -1024,7 +968,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook currentWebView.getSettings().setUseWideViewPort(false); // Load a waiting page. `null` specifies no encoding, which defaults to ASCII. - currentWebView.loadData(waitingForOrbotHtmlString, "text/html", null); + currentWebView.loadData("

" + getString(R.string.waiting_for_orbot) + "

", "text/html", null); } if (displayingFullScreenVideo || inFullScreenBrowsingMode) { @@ -1111,13 +1055,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem toggleSaveFormDataMenuItem = menu.findItem(R.id.toggle_save_form_data); // Form data can be removed once the minimum API >= 26. MenuItem clearFormDataMenuItem = menu.findItem(R.id.clear_form_data); // Form data can be removed once the minimum API >= 26. MenuItem refreshMenuItem = menu.findItem(R.id.refresh); - blocklistsMenuItem = menu.findItem(R.id.blocklists); - easyListMenuItem = menu.findItem(R.id.easylist); - easyPrivacyMenuItem = menu.findItem(R.id.easyprivacy); - fanboysAnnoyanceListMenuItem = menu.findItem(R.id.fanboys_annoyance_list); - fanboysSocialBlockingListMenuItem = menu.findItem(R.id.fanboys_social_blocking_list); - ultraPrivacyMenuItem = menu.findItem(R.id.ultraprivacy); - blockAllThirdPartyRequestsMenuItem = menu.findItem(R.id.block_all_third_party_requests); MenuItem adConsentMenuItem = menu.findItem(R.id.ad_consent); // Only display third-party cookies if API >= 21 @@ -1181,6 +1118,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem clearCookiesMenuItem = menu.findItem(R.id.clear_cookies); MenuItem clearDOMStorageMenuItem = menu.findItem(R.id.clear_dom_storage); MenuItem clearFormDataMenuItem = menu.findItem(R.id.clear_form_data); // Form data can be removed once the minimum API >= 26. + MenuItem blocklistsMenuItem = menu.findItem(R.id.blocklists); + MenuItem easyListMenuItem = menu.findItem(R.id.easylist); + MenuItem easyPrivacyMenuItem = menu.findItem(R.id.easyprivacy); + MenuItem fanboysAnnoyanceListMenuItem = menu.findItem(R.id.fanboys_annoyance_list); + MenuItem fanboysSocialBlockingListMenuItem = menu.findItem(R.id.fanboys_social_blocking_list); + MenuItem ultraPrivacyMenuItem = menu.findItem(R.id.ultraprivacy); + MenuItem blockAllThirdPartyRequestsMenuItem = menu.findItem(R.id.block_all_third_party_requests); MenuItem fontSizeMenuItem = menu.findItem(R.id.font_size); MenuItem swipeToRefreshMenuItem = menu.findItem(R.id.swipe_to_refresh); MenuItem displayImagesMenuItem = menu.findItem(R.id.display_images); @@ -1251,6 +1195,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Enable Clear Cookies if there are any. clearCookiesMenuItem.setEnabled(cookieManager.hasCookies()); + // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`. + String privateDataDirectoryString = getApplicationInfo().dataDir; + // Get a count of the number of files in the Local Storage directory. File localStorageDirectory = new File (privateDataDirectoryString + "/app_webview/Local Storage/"); int localStorageDirectoryNumberOfFiles = 0; @@ -1577,20 +1524,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`. @Override public void onDismissed(Snackbar snackbar, int event) { - switch (event) { - // The user pushed the undo button. - case Snackbar.Callback.DISMISS_EVENT_ACTION: - // Do nothing. - break; - - // The snackbar was dismissed without the undo button being pushed. - default: - // `cookieManager.removeAllCookie()` varies by SDK. - if (Build.VERSION.SDK_INT < 21) { - cookieManager.removeAllCookie(); - } else { - cookieManager.removeAllCookies(null); - } + if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { // The snackbar was dismissed without the undo button being pushed. + // Delete the cookies, which command varies by SDK. + if (Build.VERSION.SDK_INT < 21) { + cookieManager.removeAllCookie(); + } else { + cookieManager.removeAllCookies(null); + } } } }) @@ -1606,49 +1546,46 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`. @Override public void onDismissed(Snackbar snackbar, int event) { - switch (event) { - // The user pushed the undo button. - case Snackbar.Callback.DISMISS_EVENT_ACTION: - // Do nothing. - break; - - // The snackbar was dismissed without the undo button being pushed. - default: - // Delete the DOM Storage. - WebStorage webStorage = WebStorage.getInstance(); - webStorage.deleteAllData(); - - // Initialize a handler to manually delete the DOM storage files and directories. - Handler deleteDomStorageHandler = new Handler(); - - // Setup a runnable to manually delete the DOM storage files and directories. - Runnable deleteDomStorageRunnable = () -> { - try { - // Get a handle for the runtime. - Runtime runtime = Runtime.getRuntime(); - - // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly. - Process deleteLocalStorageProcess = runtime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"}); - - // Multiple commands must be used because `Runtime.exec()` does not like `*`. - Process deleteIndexProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB"); - Process deleteQuotaManagerProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager"); - Process deleteQuotaManagerJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal"); - Process deleteDatabasesProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases"); - - // Wait for the processes to finish. - deleteLocalStorageProcess.waitFor(); - deleteIndexProcess.waitFor(); - deleteQuotaManagerProcess.waitFor(); - deleteQuotaManagerJournalProcess.waitFor(); - deleteDatabasesProcess.waitFor(); - } catch (Exception exception) { - // Do nothing if an error is thrown. - } - }; - - // Manually delete the DOM storage files after 200 milliseconds. - deleteDomStorageHandler.postDelayed(deleteDomStorageRunnable, 200); + if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { // The snackbar was dismissed without the undo button being pushed. + // Delete the DOM Storage. + WebStorage webStorage = WebStorage.getInstance(); + webStorage.deleteAllData(); + + // Initialize a handler to manually delete the DOM storage files and directories. + Handler deleteDomStorageHandler = new Handler(); + + // Setup a runnable to manually delete the DOM storage files and directories. + Runnable deleteDomStorageRunnable = () -> { + try { + // Get a handle for the runtime. + Runtime runtime = Runtime.getRuntime(); + + // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, + // which links to `/data/data/com.stoutner.privacybrowser.standard`. + String privateDataDirectoryString = getApplicationInfo().dataDir; + + // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly. + Process deleteLocalStorageProcess = runtime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"}); + + // Multiple commands must be used because `Runtime.exec()` does not like `*`. + Process deleteIndexProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB"); + Process deleteQuotaManagerProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager"); + Process deleteQuotaManagerJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal"); + Process deleteDatabasesProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases"); + + // Wait for the processes to finish. + deleteLocalStorageProcess.waitFor(); + deleteIndexProcess.waitFor(); + deleteQuotaManagerProcess.waitFor(); + deleteQuotaManagerJournalProcess.waitFor(); + deleteDatabasesProcess.waitFor(); + } catch (Exception exception) { + // Do nothing if an error is thrown. + } + }; + + // Manually delete the DOM storage files after 200 milliseconds. + deleteDomStorageHandler.postDelayed(deleteDomStorageRunnable, 200); } } }) @@ -1665,17 +1602,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`. @Override public void onDismissed(Snackbar snackbar, int event) { - switch (event) { - // The user pushed the undo button. - case Snackbar.Callback.DISMISS_EVENT_ACTION: - // Do nothing. - break; - - // The snackbar was dismissed without the `Undo` button being pushed. - default: - // Delete the form data. - WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(getApplicationContext()); - mainWebViewDatabase.clearFormData(); + if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { // The snackbar was dismissed without the undo button being pushed. + // Delete the form data. + WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(getApplicationContext()); + mainWebViewDatabase.clearFormData(); } } }) @@ -1933,7 +1863,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook currentWebView.getSettings().setJavaScriptEnabled(true); } else if (currentWebView.getDomainSettingsApplied()) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings. // Apply the JavaScript preference that was stored the last time domain settings were loaded. - currentWebView.getSettings().setJavaScriptEnabled(domainSettingsJavaScriptEnabled); // TODO. + currentWebView.getSettings().setJavaScriptEnabled(currentWebView.getDomainSettingsJavaScriptEnabled()); } else { // Night mode is disabled and domain settings are not applied. Set JavaScript according to the global preference. // Apply the JavaScript preference. currentWebView.getSettings().setJavaScriptEnabled(sharedPreferences.getBoolean("javascript", false)); @@ -2062,7 +1992,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // removeAllCookies is deprecated, but it is required for API < 21. - @SuppressWarnings("deprecation") @Override public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { // Get the menu item ID. @@ -2101,6 +2030,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get a handle for the runtime. Runtime runtime = Runtime.getRuntime(); + // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, + // which links to `/data/data/com.stoutner.privacybrowser.standard`. + String privateDataDirectoryString = getApplicationInfo().dataDir; + // Clear cookies. if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) { // The command to remove cookies changed slightly in API 21. @@ -2276,8 +2209,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Reset the current domain name so that navigation works if third-party requests are blocked. currentWebView.resetCurrentDomainName(); - // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded. - navigatingHistory = true; + // Set navigating history so that the domain settings are applied when the new URL is loaded. + currentWebView.setNavigatingHistory(true); // Load the previous website in the history. currentWebView.goBack(); @@ -2289,8 +2222,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Reset the current domain name so that navigation works if third-party requests are blocked. currentWebView.resetCurrentDomainName(); - // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded. - navigatingHistory = true; + // Set navigating history so that the domain settings are applied when the new URL is loaded. + currentWebView.setNavigatingHistory(true); // Load the next website in the history. currentWebView.goForward(); @@ -2380,8 +2313,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook break; case R.id.about: - // Launch `AboutActivity`. + // Create an intent to launch the about activity. Intent aboutIntent = new Intent(this, AboutActivity.class); + + // Create a string array for the blocklist versions. + String[] blocklistVersions = new String[] {easyList.get(0).get(0)[0], easyPrivacy.get(0).get(0)[0], fanboysAnnoyanceList.get(0).get(0)[0], fanboysSocialList.get(0).get(0)[0], + ultraPrivacy.get(0).get(0)[0]}; + + // Add the blocklist versions to the intent. + aboutIntent.putExtra("blocklist_versions", blocklistVersions); + + // Make it so. startActivity(aboutIntent); break; } @@ -2440,9 +2382,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook final String imageUrl; final String linkUrl; - // Get handles for the the clipboard and fragment managers. + // Get handles for the system managers. final ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); FragmentManager fragmentManager = getSupportFragmentManager(); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); // Remove the lint errors below that the clipboard manager might be null. assert clipboardManager != null; @@ -2492,7 +2435,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a Download URL entry. menu.add(R.string.download_url).setOnMenuItemClickListener((MenuItem item) -> { // Check if the download should be processed by an external app. - if (downloadWithExternalApp) { // Download with an external app. + if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app. openUrlWithExternalApp(linkUrl); } else { // Download with Android's download manager. // Check to see if the storage permission has already been granted. @@ -2582,7 +2525,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a Download Image entry. menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> { // Check if the download should be processed by an external app. - if (downloadWithExternalApp) { // Download with an external app. + if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app. openUrlWithExternalApp(imageUrl); } else { // Download with Android's download manager. // Check to see if the storage permission has already been granted. @@ -2656,7 +2599,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a `Download Image` entry. menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> { // Check if the download should be processed by an external app. - if (downloadWithExternalApp) { // Download with an external app. + if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app. openUrlWithExternalApp(imageUrl); } else { // Download with Android's download manager. // Check to see if the storage permission has already been granted. @@ -3093,40 +3036,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - @Override - public void onHttpAuthenticationCancel() { - // Cancel the `HttpAuthHandler`. - httpAuthHandler.cancel(); - } - - @Override - public void onHttpAuthenticationProceed(DialogFragment dialogFragment) { - // Get handles for the `EditTexts`. - EditText usernameEditText = dialogFragment.getDialog().findViewById(R.id.http_authentication_username); - EditText passwordEditText = dialogFragment.getDialog().findViewById(R.id.http_authentication_password); - - // Proceed with the HTTP authentication. - httpAuthHandler.proceed(usernameEditText.getText().toString(), passwordEditText.getText().toString()); - } - - @Override - public void onSslErrorCancel() { // TODO. How to handle this with multiple tabs? There could be multiple errors at once. - sslErrorHandler.cancel(); - } - - @Override - public void onSslErrorProceed() { // TODO. How to handle this with multiple tabs? There could be multiple errors at once. - sslErrorHandler.proceed(); - } - @Override public void onPinnedMismatchBack() { // TODO. Move this logic to the dialog. if (currentWebView.canGoBack()) { // There is a back page in the history. // Reset the current domain name so that navigation works if third-party requests are blocked. currentWebView.resetCurrentDomainName(); - // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded. - navigatingHistory = true; // TODO. + // Set navigating history so that the domain settings are applied when the new URL is loaded. + currentWebView.setNavigatingHistory(true); // Go back. currentWebView.goBack(); @@ -3143,19 +3060,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onUrlHistoryEntrySelected(int moveBackOrForwardSteps) { + public void onUrlHistoryEntrySelected(int moveBackOrForwardSteps) { // TODO. Move this logic to the dialog. // Reset the current domain name so that navigation works if third-party requests are blocked. currentWebView.resetCurrentDomainName(); - // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded. - navigatingHistory = true; + // Set navigating history so that the domain settings are applied when the new URL is loaded. + currentWebView.setNavigatingHistory(true); // Load the history entry. currentWebView.goBackOrForward(moveBackOrForwardSteps); } @Override - public void onClearHistory() { + public void onClearHistory() { // TODO. Move this logic to the dialog. // Clear the history. currentWebView.clearHistory(); } @@ -3184,8 +3101,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Reset the current domain name so that navigation works if third-party requests are blocked. currentWebView.resetCurrentDomainName(); - // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded. - navigatingHistory = true; + // Set navigating history so that the domain settings are applied when the new URL is loaded. + currentWebView.setNavigatingHistory(true); // Go back. currentWebView.goBack(); @@ -3331,7 +3248,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false); fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false); hideAppBar = sharedPreferences.getBoolean("hide_app_bar", true); - downloadWithExternalApp = sharedPreferences.getBoolean("download_with_external_app", false); // Get handles for the views that need to be modified. `getSupportActionBar()` must be used until the minimum API >= 21. FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout); @@ -3553,7 +3469,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the settings from the cursor. nestedScrollWebView.setDomainSettingsDatabaseId(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); - boolean domainJavaScriptEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); + nestedScrollWebView.setDomainSettingsJavaScriptEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); nestedScrollWebView.setAcceptFirstPartyCookies(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1); boolean domainThirdPartyCookiesEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1); nestedScrollWebView.getSettings().setDomStorageEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1); @@ -3633,17 +3549,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook break; } - // TODO. - // Store the domain JavaScript status. This is used by the options menu night mode toggle. - domainSettingsJavaScriptEnabled = domainJavaScriptEnabled; - // Enable JavaScript if night mode is enabled. if (nestedScrollWebView.getNightMode()) { // Enable JavaScript. nestedScrollWebView.getSettings().setJavaScriptEnabled(true); } else { // Set JavaScript according to the domain settings. - nestedScrollWebView.getSettings().setJavaScriptEnabled(domainJavaScriptEnabled); + nestedScrollWebView.getSettings().setJavaScriptEnabled(nestedScrollWebView.getDomainSettingsJavaScriptEnabled()); } // Close the current host domain settings cursor. @@ -3910,7 +3822,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook currentWebView.getSettings().setUseWideViewPort(false); // Load a waiting page. `null` specifies no encoding, which defaults to ASCII. - currentWebView.loadData(waitingForOrbotHtmlString, "text/html", null); + currentWebView.loadData("

" + getString(R.string.waiting_for_orbot) + "

", "text/html", null); } else if (reloadWebsite) { // Orbot is ready and the website should be reloaded. // Reload the website. currentWebView.reload(); @@ -4233,63 +4145,63 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the fragment view. View fragmentView = webViewTabFragment.getView(); - // Remove the incorrect lint warning below that the fragment view might be null. - assert fragmentView != null; - - // Store the current WebView. - currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + // Set the current WebView if the fragment view is not null. + if (fragmentView != null) { + // Store the current WebView. + currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview); - // Update the status of swipe to refresh. - if (currentWebView.getSwipeToRefresh()) { // Swipe to refresh is enabled. - if (Build.VERSION.SDK_INT >= 23) { // For API >= 23, swipe refresh layout is continuously updated with an on scroll change listener and only enabled if the WebView is scrolled to the top. - // Enable the swipe refresh layout if the WebView is scrolled all the way to the top. - swipeRefreshLayout.setEnabled(currentWebView.getY() == 0); - } else { - // Enable the swipe refresh layout. - swipeRefreshLayout.setEnabled(true); + // Update the status of swipe to refresh. + if (currentWebView.getSwipeToRefresh()) { // Swipe to refresh is enabled. + if (Build.VERSION.SDK_INT >= 23) { // For API >= 23, swipe refresh layout is continuously updated with an on scroll change listener and only enabled if the WebView is scrolled to the top. + // Enable the swipe refresh layout if the WebView is scrolled all the way to the top. + swipeRefreshLayout.setEnabled(currentWebView.getY() == 0); + } else { + // Enable the swipe refresh layout. + swipeRefreshLayout.setEnabled(true); + } + } else { // Swipe to refresh is disabled. + // Disable the swipe refresh layout. + swipeRefreshLayout.setEnabled(false); } - } else { // Swipe to refresh is disabled. - // Disable the swipe refresh layout. - swipeRefreshLayout.setEnabled(false); - } - // Get a handle for the cookie manager. - CookieManager cookieManager = CookieManager.getInstance(); + // Get a handle for the cookie manager. + CookieManager cookieManager = CookieManager.getInstance(); - // Set the first-party cookie status. - cookieManager.setAcceptCookie(currentWebView.getAcceptFirstPartyCookies()); + // Set the first-party cookie status. + cookieManager.setAcceptCookie(currentWebView.getAcceptFirstPartyCookies()); - // Update the privacy icons. `true` redraws the icons in the app bar. - updatePrivacyIcons(true); + // Update the privacy icons. `true` redraws the icons in the app bar. + updatePrivacyIcons(true); - // Clear the focus from the URL text box. - urlEditText.clearFocus(); + // Clear the focus from the URL text box. + urlEditText.clearFocus(); - // Get a handle for the input method manager. - InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + // Get a handle for the input method manager. + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - // Remove the lint warning below that the input method manager might be null. - assert inputMethodManager != null; + // Remove the lint warning below that the input method manager might be null. + assert inputMethodManager != null; - // Hide the soft keyboard. - inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); + // Hide the soft keyboard. + inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); - // Display the current URL in the URL text box. - urlEditText.setText(currentWebView.getUrl()); + // Display the current URL in the URL text box. + urlEditText.setText(currentWebView.getUrl()); - // Highlight the URL text. - highlightUrlText(); + // Highlight the URL text. + highlightUrlText(); - // Set the background to indicate the domain settings status. - if (currentWebView.getDomainSettingsApplied()) { - // Set a green background on the URL relative layout to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. - if (darkTheme) { - urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + // Set the background to indicate the domain settings status. + if (currentWebView.getDomainSettingsApplied()) { + // Set a green background on the URL relative layout to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + if (darkTheme) { + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + } else { + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + } } else { - urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent)); } - } else { - urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent)); } } @@ -4313,6 +4225,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get a handle for the input method manager. InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + // Instantiate the blocklist helper. + BlockListHelper blockListHelper = new BlockListHelper(); + // Remove the lint warning below that the input method manager might be null. assert inputMethodManager != null; @@ -4563,20 +4478,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the current tab. TabLayout.Tab tab = tabLayout.getTabAt(currentPosition); - // Remove the lint warning below that the current tab might be null. - assert tab != null; - - // Get the custom view from the tab. - View tabView = tab.getCustomView(); - - // Remove the incorrect warning below that the current tab view might be null. - assert tabView != null; + // Check to see if the tab has been populated. + if (tab != null) { + // Get the custom view from the tab. + View tabView = tab.getCustomView(); - // Get the favorite icon image view from the tab. - ImageView tabFavoriteIconImageView = tabView.findViewById(R.id.favorite_icon_imageview); + // Check to see if the custom tab view has been populated. + if (tabView != null) { + // Get the favorite icon image view from the tab. + ImageView tabFavoriteIconImageView = tabView.findViewById(R.id.favorite_icon_imageview); - // Display the favorite icon in the tab. - tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true)); + // Display the favorite icon in the tab. + tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true)); + } + } } } @@ -4672,7 +4587,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Show the main content relative layout. mainContentRelativeLayout.setVisibility(View.VISIBLE); - // Apply the appropriate full screen mode the `SYSTEM_UI` flags. + // Apply the appropriate full screen mode flags. if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) { // Privacy Browser is currently in full screen browsing mode. // Hide the app bar if specified. if (hideAppBar) { @@ -4731,7 +4646,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.setWebViewClient(new WebViewClient() { // `shouldOverrideUrlLoading` makes this `WebView` the default handler for URLs inside the app, so that links are not kicked out to other apps. // The deprecated `shouldOverrideUrlLoading` must be used until API >= 24. - @SuppressWarnings("deprecation") @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith("http")) { // Load the URL in Privacy Browser. @@ -4805,7 +4719,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // 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) { // Get a handle for the navigation view. @@ -4817,6 +4730,15 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get a handle for the navigation requests menu item. The menu is 0 based. MenuItem navigationRequestsMenuItem = navigationMenu.getItem(6); + // Get handles for the options menu items. + MenuItem blocklistsMenuItem = optionsMenu.findItem(R.id.blocklists); + MenuItem easyListMenuItem = optionsMenu.findItem(R.id.easylist); + MenuItem easyPrivacyMenuItem = optionsMenu.findItem(R.id.easyprivacy); + MenuItem fanboysAnnoyanceListMenuItem = optionsMenu.findItem(R.id.fanboys_annoyance_list); + MenuItem fanboysSocialBlockingListMenuItem = optionsMenu.findItem(R.id.fanboys_social_blocking_list); + MenuItem ultraPrivacyMenuItem = optionsMenu.findItem(R.id.ultraprivacy); + MenuItem blockAllThirdPartyRequestsMenuItem = optionsMenu.findItem(R.id.block_all_third_party_requests); + // Create an empty web resource response to be used if the resource request is blocked. WebResourceResponse emptyWebResourceResponse = new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); @@ -5078,11 +5000,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Handle HTTP authentication requests. @Override public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { - // Store `handler` so it can be accessed from `onHttpAuthenticationCancel()` and `onHttpAuthenticationProceed()`. - httpAuthHandler = handler; + // Store the handler. + nestedScrollWebView.setHttpAuthHandler(handler); - // Display the HTTP authentication dialog. - DialogFragment httpAuthenticationDialogFragment = HttpAuthenticationDialog.displayDialog(host, realm); + // Instantiate an HTTP authentication dialog. + DialogFragment httpAuthenticationDialogFragment = HttpAuthenticationDialog.displayDialog(host, realm, nestedScrollWebView.getWebViewFragmentId()); + + // Show the HTTP authentication dialog. httpAuthenticationDialogFragment.show(getSupportFragmentManager(), getString(R.string.http_authentication)); } @@ -5123,13 +5047,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost()); // Apply any custom domain settings if the URL was loaded by navigating history. - if (navigatingHistory) { + if (nestedScrollWebView.getNavigatingHistory()) { + // Reset navigating history. + nestedScrollWebView.setNavigatingHistory(false); + // Apply the domain settings. boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false); - // Reset `navigatingHistory`. - navigatingHistory = false; - // Manually load the URL if the user agent has changed, which will have caused the previous URL to be reloaded. if (userAgentChanged) { loadUrl(url); @@ -5204,6 +5128,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Manually delete cache folders. try { + // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, + // which links to `/data/data/com.stoutner.privacybrowser.standard`. + String privateDataDirectoryString = getApplicationInfo().dataDir; + // Delete the main cache directory. Runtime.getRuntime().exec("rm -rf " + privateDataDirectoryString + "/cache"); @@ -5287,11 +5215,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook handler.proceed(); } } else { // Either there isn't a pinned SSL certificate or it doesn't match the current website certificate. - // Store `handler` so it can be accesses from `onSslErrorCancel()` and `onSslErrorProceed()`. - sslErrorHandler = handler; // TODO. We need to pass this in instead of using a static variable. Because multiple could be displayed at once from different tabs. + // Store the SSL error handler. + nestedScrollWebView.setSslErrorHandler(handler); + + // Instantiate an SSL certificate error alert dialog. + DialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error, nestedScrollWebView.getWebViewFragmentId()); - // Display the SSL error `AlertDialog`. - DialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error); + // Show the SSL certificate error dialog. sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_error)); } } diff --git a/app/src/main/java/com/stoutner/privacybrowser/adapters/AboutPagerAdapter.java b/app/src/main/java/com/stoutner/privacybrowser/adapters/AboutPagerAdapter.java new file mode 100644 index 00000000..0d9a1586 --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/adapters/AboutPagerAdapter.java @@ -0,0 +1,88 @@ +/* + * Copyright © 2016-2019 Soren Stoutner . + * + * This file is part of Privacy Browser . + * + * Privacy Browser is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser. If not, see . + */ + +package com.stoutner.privacybrowser.adapters; + +import android.content.Context; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import com.stoutner.privacybrowser.R; +import com.stoutner.privacybrowser.fragments.AboutTabFragment; + +public class AboutPagerAdapter extends FragmentPagerAdapter { + // Define the class variable to store the blocklist versions. + private Context context; + private String[] blocklistVersions; + + public AboutPagerAdapter(FragmentManager fragmentManager, Context context, String[] blocklistVersions) { + // Run the default commands. + super(fragmentManager); + + // Store the context in a class variable. + this.context = context; + + // Store the blocklist versions in a class variable. + this.blocklistVersions = blocklistVersions; + } + + @Override + // Get the count of the number of tabs. + public int getCount() { + return 7; + } + + @Override + // Get the name of each tab. Tab numbers start at 0. + public CharSequence getPageTitle(int tab) { + switch (tab) { + case 0: + return context.getResources().getString(R.string.version); + + case 1: + return context.getResources().getString(R.string.permissions); + + case 2: + return context.getResources().getString(R.string.privacy_policy); + + case 3: + return context.getResources().getString(R.string.changelog); + + case 4: + return context.getResources().getString(R.string.licenses); + + case 5: + return context.getResources().getString(R.string.contributors); + + case 6: + return context.getResources().getString(R.string.links); + + default: + return ""; + } + } + + @Override + // Setup each tab. + public Fragment getItem(int tabNumber) { + return AboutTabFragment.createTab(tabNumber, blocklistVersions); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewSourceDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewSourceDialog.java index e4f558b6..e163ac54 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewSourceDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewSourceDialog.java @@ -64,7 +64,7 @@ public class AboutViewSourceDialog extends DialogFragment { dialogBuilder.setMessage(R.string.about_view_source_message); // Create an alert dialog from the alert dialog builder. - final AlertDialog alertDialog = dialogBuilder.create(); + AlertDialog alertDialog = dialogBuilder.create(); // Disable screenshots if not allowed. if (!allowScreenshots) { @@ -75,7 +75,7 @@ public class AboutViewSourceDialog extends DialogFragment { alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } - // `onCreateDialog` requires the return of an `AlertDialog`. + // Return the alert dialog. return alertDialog; } } diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/HttpAuthenticationDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/HttpAuthenticationDialog.java index c04bf8ff..7ee7dd01 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/HttpAuthenticationDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/HttpAuthenticationDialog.java @@ -22,7 +22,6 @@ package com.stoutner.privacybrowser.dialogs; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; -import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; @@ -34,6 +33,7 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; +import android.webkit.HttpAuthHandler; import android.widget.EditText; import android.widget.TextView; @@ -41,34 +41,31 @@ import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22. import com.stoutner.privacybrowser.R; +import com.stoutner.privacybrowser.activities.MainWebViewActivity; +import com.stoutner.privacybrowser.fragments.WebViewTabFragment; +import com.stoutner.privacybrowser.views.NestedScrollWebView; public class HttpAuthenticationDialog extends DialogFragment{ - // `httpAuthenticationListener` is used in `onAttach()` and `onCreateDialog()` - private HttpAuthenticationListener httpAuthenticationListener; + // Define the class variables. + private EditText usernameEditText; + private EditText passwordEditText; - // The public interface is used to send information back to the parent activity. - public interface HttpAuthenticationListener { - void onHttpAuthenticationCancel(); - - void onHttpAuthenticationProceed(DialogFragment dialogFragment); - } - - public void onAttach(Context context) { - super.onAttach(context); - - // Get a handle for `httpAuthenticationListener` from `context`. - httpAuthenticationListener = (HttpAuthenticationListener) context; - } - - public static HttpAuthenticationDialog displayDialog(String host, String realm) { - // Store the strings in a `Bundle`. + public static HttpAuthenticationDialog displayDialog(String host, String realm, long webViewFragmentId) { + // Create an arguments bundle. Bundle argumentsBundle = new Bundle(); - argumentsBundle.putString("Host", host); - argumentsBundle.putString("Realm", realm); - // Add `argumentsBundle` to this instance of `HttpAuthenticationDialog`. + // Store the variables in the bundle. + argumentsBundle.putString("host", host); + argumentsBundle.putString("realm", realm); + argumentsBundle.putLong("webview_fragment_id", webViewFragmentId); + + // Create a new instance of the HTTP authentication dialog. HttpAuthenticationDialog thisHttpAuthenticationDialog = new HttpAuthenticationDialog(); + + // Add the arguments bundle to the new dialog. thisHttpAuthenticationDialog.setArguments(argumentsBundle); + + // Return the new dialog. return thisHttpAuthenticationDialog; } @@ -77,12 +74,34 @@ public class HttpAuthenticationDialog extends DialogFragment{ @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - // Remove the incorrect lint warnings that `getString()` might be null. - assert getArguments() != null; + // Get a handle for the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning below that arguments might be null. + assert arguments != null; - // Get the host and realm variables from the bundle. - String httpAuthHost = getArguments().getString("Host"); - String httpAuthRealm = getArguments().getString("Realm"); + // Get the variables from the bundle. + String httpAuthHost = arguments.getString("host"); + String httpAuthRealm = arguments.getString("realm"); + long webViewFragmentId = arguments.getLong("webview_fragment_id"); + + // Get the current position of this WebView fragment. + int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId); + + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition); + + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Remove the incorrect lint warning below that the fragment view might be null. + assert fragmentView != null; + + // Get a handle for the current WebView. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Get a handle for the HTTP authentication handler. + HttpAuthHandler httpAuthHandler = nestedScrollWebView.getHttpAuthHandler(); // Remove the incorrect lint warning that `getActivity()` might be null. assert getActivity() != null; @@ -121,16 +140,22 @@ public class HttpAuthenticationDialog extends DialogFragment{ // Set the layout. The parent view is `null` because it will be assigned by `AlertDialog`. dialogBuilder.setView(layoutInflater.inflate(R.layout.http_authentication_dialog, null)); - // Setup the negative button. + // Setup the close button. dialogBuilder.setNegativeButton(R.string.close, (DialogInterface dialog, int which) -> { - // Call `onHttpAuthenticationCancel()` and return the `DialogFragment` to the parent activity. - httpAuthenticationListener.onHttpAuthenticationCancel(); + // Cancel the HTTP authentication request. + httpAuthHandler.cancel(); + + // Reset the HTTP authentication handler. + nestedScrollWebView.resetHttpAuthHandler(); }); - // Setup the positive button. + // Setup the proceed button. dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> { - // Call `onHttpAuthenticationProceed()` and return the `DialogFragment` to the parent activity. - httpAuthenticationListener.onHttpAuthenticationProceed(HttpAuthenticationDialog.this); + // Send the login information + login(httpAuthHandler); + + // Reset the HTTP authentication handler. + nestedScrollWebView.resetHttpAuthHandler(); }); // Create an alert dialog from the alert dialog builder. @@ -144,27 +169,25 @@ public class HttpAuthenticationDialog extends DialogFragment{ alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } - // Show the keyboard when the `AlertDialog` is displayed on the screen. + // Show the keyboard when the alert dialog is displayed on the screen. alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); // The alert dialog needs to be shown before the contents can be modified. alertDialog.show(); - // Get handles for the views in `alertDialog`. + // Get handles for the views. TextView realmTextView = alertDialog.findViewById(R.id.http_authentication_realm); TextView hostTextView = alertDialog.findViewById(R.id.http_authentication_host); - EditText usernameEditText = alertDialog.findViewById(R.id.http_authentication_username); - EditText passwordEditText = alertDialog.findViewById(R.id.http_authentication_password); + usernameEditText = alertDialog.findViewById(R.id.http_authentication_username); + passwordEditText = alertDialog.findViewById(R.id.http_authentication_password); // Set the realm text. realmTextView.setText(httpAuthRealm); // Set the realm text color according to the theme. The deprecated `.getColor()` must be used until API >= 23. if (darkTheme) { - //noinspection deprecation realmTextView.setTextColor(getResources().getColor(R.color.gray_300)); } else { - //noinspection deprecation realmTextView.setTextColor(getResources().getColor(R.color.black)); } @@ -177,10 +200,8 @@ public class HttpAuthenticationDialog extends DialogFragment{ // Set `blueColorSpan` according to the theme. The deprecated `getColor()` must be used until API >= 23. if (darkTheme) { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400)); } else { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700)); } @@ -194,10 +215,10 @@ public class HttpAuthenticationDialog extends DialogFragment{ usernameEditText.setOnKeyListener((View view, int keyCode, KeyEvent event) -> { // If the event is a key-down on the `enter` key, call `onHttpAuthenticationProceed()`. if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) { - // Trigger `onHttpAuthenticationProceed` and return the `DialogFragment` to the parent activity. - httpAuthenticationListener.onHttpAuthenticationProceed(HttpAuthenticationDialog.this); + // Send the login information. + login(httpAuthHandler); - // Manually dismiss the `AlertDialog`. + // Manually dismiss the alert dialog. alertDialog.dismiss(); // Consume the event. @@ -211,10 +232,10 @@ public class HttpAuthenticationDialog extends DialogFragment{ passwordEditText.setOnKeyListener((View view, int keyCode, KeyEvent event) -> { // If the event is a key-down on the `enter` key, call `onHttpAuthenticationProceed()`. if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) { - // Trigger `onHttpAuthenticationProceed` and return the `DialogFragment` to the parent activity. - httpAuthenticationListener.onHttpAuthenticationProceed(HttpAuthenticationDialog.this); + // Send the login information. + login(httpAuthHandler); - // Manually dismiss the `AlertDialog`. + // Manually dismiss the alert dialog. alertDialog.dismiss(); // Consume the event. @@ -224,7 +245,12 @@ public class HttpAuthenticationDialog extends DialogFragment{ } }); - // `onCreateDialog()` requires the return of an `AlertDialog`. + // Return the alert dialog. return alertDialog; } + + private void login(HttpAuthHandler httpAuthHandler) { + // Send the login information. + httpAuthHandler.proceed(usernameEditText.getText().toString(), passwordEditText.getText().toString()); + } } \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java index fbc3293d..fbf1f90f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java @@ -428,17 +428,15 @@ public class PinnedMismatchDialog extends DialogFragment { boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false); // Create a red foreground color span. The deprecated `getResources().getColor` must be used until the minimum API >= 23. - @SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700)); + ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700)); // Create a blue foreground color span. ForegroundColorSpan blueColorSpan; // Set the blue color span according to the theme. The deprecated `getResources().getColor` must be used until the minimum API >= 23. if (darkTheme) { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400)); } else { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700)); } diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.java index 5f46d4f1..7d8e0b63 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.java @@ -23,7 +23,6 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; -import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.net.Uri; @@ -36,13 +35,18 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; +import android.view.View; import android.view.WindowManager; +import android.webkit.SslErrorHandler; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22. import com.stoutner.privacybrowser.R; +import com.stoutner.privacybrowser.activities.MainWebViewActivity; +import com.stoutner.privacybrowser.fragments.WebViewTabFragment; +import com.stoutner.privacybrowser.views.NestedScrollWebView; import java.lang.ref.WeakReference; import java.net.InetAddress; @@ -51,25 +55,7 @@ import java.text.DateFormat; import java.util.Date; public class SslCertificateErrorDialog extends DialogFragment { - // `sslCertificateErrorListener` is used in `onAttach` and `onCreateDialog`. - private SslCertificateErrorListener sslCertificateErrorListener; - - // The public interface is used to send information back to the parent activity. - public interface SslCertificateErrorListener { - void onSslErrorCancel(); - - void onSslErrorProceed(); - } - - public void onAttach(Context context) { - // Run the default commands. - super.onAttach(context); - - // Get a handle for `SslCertificateErrorListener` from the launching context. - sslCertificateErrorListener = (SslCertificateErrorListener) context; - } - - public static SslCertificateErrorDialog displayDialog(SslError error) { + public static SslCertificateErrorDialog displayDialog(SslError error, long webViewFragmentId) { // Get the various components of the SSL error message. int primaryErrorIntForBundle = error.getPrimaryError(); String urlWithErrorForBundle = error.getUrl(); @@ -83,45 +69,73 @@ public class SslCertificateErrorDialog extends DialogFragment { Date startDateForBundle = sslCertificate.getValidNotBeforeDate(); Date endDateForBundle = sslCertificate.getValidNotAfterDate(); - // Store the SSL error message components in a `Bundle`. + // Create an arguments bundle. Bundle argumentsBundle = new Bundle(); - argumentsBundle.putInt("PrimaryErrorInt", primaryErrorIntForBundle); - argumentsBundle.putString("UrlWithError", urlWithErrorForBundle); - argumentsBundle.putString("IssuedToCName", issuedToCNameForBundle); - argumentsBundle.putString("IssuedToOName", issuedToONameForBundle); - argumentsBundle.putString("IssuedToUName", issuedToUNameForBundle); - argumentsBundle.putString("IssuedByCName", issuedByCNameForBundle); - argumentsBundle.putString("IssuedByOName", issuedByONameForBundle); - argumentsBundle.putString("IssuedByUName", issuedByUNameForBundle); - argumentsBundle.putString("StartDate", DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(startDateForBundle)); - argumentsBundle.putString("EndDate", DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(endDateForBundle)); - - // Add `argumentsBundle` to this instance of `SslCertificateErrorDialog`. + + // Store the SSL error message components in a `Bundle`. + argumentsBundle.putInt("primary_error_int", primaryErrorIntForBundle); + argumentsBundle.putString("url_with_error", urlWithErrorForBundle); + argumentsBundle.putString("issued_to_cname", issuedToCNameForBundle); + argumentsBundle.putString("issued_to_oname", issuedToONameForBundle); + argumentsBundle.putString("issued_to_uname", issuedToUNameForBundle); + argumentsBundle.putString("issued_by_cname", issuedByCNameForBundle); + argumentsBundle.putString("issued_by_oname", issuedByONameForBundle); + argumentsBundle.putString("issued_by_uname", issuedByUNameForBundle); + argumentsBundle.putString("start_date", DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(startDateForBundle)); + argumentsBundle.putString("end_date", DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(endDateForBundle)); + argumentsBundle.putLong("webview_fragment_id", webViewFragmentId); + + // Create a new instance of the SSL certificate error dialog. SslCertificateErrorDialog thisSslCertificateErrorDialog = new SslCertificateErrorDialog(); + + // Add the arguments bundle to the new dialog. thisSslCertificateErrorDialog.setArguments(argumentsBundle); + + // Return the new dialog. return thisSslCertificateErrorDialog; } // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. @SuppressLint("InflateParams") - @SuppressWarnings("deprecation") @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - // Remove the incorrect lint warning that `getArguments()` might be null. - assert getArguments() != null; - - // Get the components of the SSL error message from the bundle. - int primaryErrorInt = getArguments().getInt("PrimaryErrorInt"); - String urlWithErrors = getArguments().getString("UrlWithError"); - String issuedToCName = getArguments().getString("IssuedToCName"); - String issuedToOName = getArguments().getString("IssuedToOName"); - String issuedToUName = getArguments().getString("IssuedToUName"); - String issuedByCName = getArguments().getString("IssuedByCName"); - String issuedByOName = getArguments().getString("IssuedByOName"); - String issuedByUName = getArguments().getString("IssuedByUName"); - String startDate = getArguments().getString("StartDate"); - String endDate = getArguments().getString("EndDate"); + // Get a handle for the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning that the arguments might be null. + assert arguments != null; + + // Get the variables from the bundle. + int primaryErrorInt = arguments.getInt("primary_error_int"); + String urlWithErrors = arguments.getString("url_with_error"); + String issuedToCName = arguments.getString("issued_to_cname"); + String issuedToOName = arguments.getString("issued_to_oname"); + String issuedToUName = arguments.getString("issued_to_uname"); + String issuedByCName = arguments.getString("issued_by_cname"); + String issuedByOName = arguments.getString("issued_by_oname"); + String issuedByUName = arguments.getString("issued_by_uname"); + String startDate = arguments.getString("start_date"); + String endDate = arguments.getString("end_date"); + long webViewFragmentId = arguments.getLong("webview_fragment_id"); + + // Get the current position of this WebView fragment. + int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId); + + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition); + + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Remove the incorrect lint warning below that the fragment view might be null. + assert fragmentView != null; + + // Get a handle for the current WebView. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Get a handle for the SSL error handler. + SslErrorHandler sslErrorHandler = nestedScrollWebView.getSslErrorHandler(); // Remove the incorrect lint warning that `getActivity()` might be null. assert getActivity() != null; @@ -160,11 +174,29 @@ public class SslCertificateErrorDialog extends DialogFragment { // Set the view. The parent view is `null` because it will be assigned by `AlertDialog`. dialogBuilder.setView(layoutInflater.inflate(R.layout.ssl_certificate_error, null)); - // Set a listener on the negative button. - dialogBuilder.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> sslCertificateErrorListener.onSslErrorCancel()); + // Set a listener on the cancel button. + dialogBuilder.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> { + // Check to make sure the SSL error handler is not null. This might happen if multiple dialogs are displayed at once. + if (sslErrorHandler != null) { + // Cancel the request. + sslErrorHandler.cancel(); + + // Reset the SSL error handler. + nestedScrollWebView.resetSslErrorHandler(); + } + }); + + // Set a listener on the proceed button. + dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> { + // Check to make sure the SSL error handler is not null. This might happen if multiple dialogs are displayed at once. + if (sslErrorHandler != null) { + // Cancel the request. + sslErrorHandler.proceed(); - // Set a listener on the positive button. - dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> sslCertificateErrorListener.onSslErrorProceed()); + // Reset the SSL error handler. + nestedScrollWebView.resetSslErrorHandler(); + } + }); // Create an alert dialog from the alert dialog builder. @@ -222,17 +254,15 @@ public class SslCertificateErrorDialog extends DialogFragment { SpannableStringBuilder endDateStringBuilder = new SpannableStringBuilder((endDateLabel + endDate)); // Create a red foreground color span. The deprecated `getResources().getColor` must be used until the minimum API >= 23. - @SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700)); + ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700)); // Create a blue `ForegroundColorSpan`. ForegroundColorSpan blueColorSpan; // Set a blue color span according to the theme. The deprecated `getResources().getColor` must be used until the minimum API >= 23. if (darkTheme) { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400)); } else { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700)); } @@ -391,10 +421,8 @@ public class SslCertificateErrorDialog extends DialogFragment { // Set the blue color span according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23. if (darkTheme) { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_400)); } else { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_700)); } diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutTabFragment.java b/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutTabFragment.java index 8c488254..4ff9a28a 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutTabFragment.java +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutTabFragment.java @@ -41,7 +41,6 @@ import androidx.fragment.app.Fragment; import com.stoutner.privacybrowser.BuildConfig; import com.stoutner.privacybrowser.R; -import com.stoutner.privacybrowser.activities.MainWebViewActivity; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -54,20 +53,23 @@ import java.text.DateFormat; import java.util.Date; public class AboutTabFragment extends Fragment { - // Track the current tab number. + // Declare the class variables. private int tabNumber; + private String[] blocklistVersions; - // Store the tab number in the arguments bundle. - public static AboutTabFragment createTab(int tab) { + public static AboutTabFragment createTab(int tabNumber, String[] blocklistVersions) { // Create a bundle. - Bundle bundle = new Bundle(); + Bundle argumentsBundle = new Bundle(); // Store the tab number in the bundle. - bundle.putInt("Tab", tab); + argumentsBundle.putInt("tab_number", tabNumber); + argumentsBundle.putStringArray("blocklist_versions", blocklistVersions); - // Add the bundle to the fragment. + // Create a new instance of the tab fragment. AboutTabFragment aboutTabFragment = new AboutTabFragment(); - aboutTabFragment.setArguments(bundle); + + // Add the arguments bundle to the fragment. + aboutTabFragment.setArguments(argumentsBundle); // Return the new fragment. return aboutTabFragment; @@ -78,11 +80,15 @@ public class AboutTabFragment extends Fragment { // Run the default commands. super.onCreate(savedInstanceState); - // Remove the lint warning that `getArguments()` might be null. - assert getArguments() != null; + // Get a handle for the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning below that arguments might be null. + assert arguments != null; - // Store the tab number in a class variable. - tabNumber = getArguments().getInt("Tab"); + // Store the arguments in class variables. + tabNumber = getArguments().getInt("tab_number"); + blocklistVersions = getArguments().getStringArray("blocklist_versions"); } @Override @@ -133,7 +139,7 @@ public class AboutTabFragment extends Fragment { TextView certificateSignatureAlgorithmTextView = tabLayout.findViewById(R.id.certificate_signature_algorithm); // Setup the labels. - String version = getString(R.string.version) + " " + BuildConfig.VERSION_NAME + " (" + getString(R.string.version_code) + " " + Integer.toString(BuildConfig.VERSION_CODE) + ")"; + String version = getString(R.string.version) + " " + BuildConfig.VERSION_NAME + " (" + getString(R.string.version_code) + " " + BuildConfig.VERSION_CODE + ")"; String brandLabel = getString(R.string.brand) + " "; String manufacturerLabel = getString(R.string.manufacturer) + " "; String modelLabel = getString(R.string.model) + " "; @@ -167,7 +173,7 @@ public class AboutTabFragment extends Fragment { String device = Build.DEVICE; String bootloader = Build.BOOTLOADER; String radio = Build.getRadioVersion(); - String android = Build.VERSION.RELEASE + " (" + getString(R.string.api) + " " + Integer.toString(Build.VERSION.SDK_INT) + ")"; + String android = Build.VERSION.RELEASE + " (" + getString(R.string.api) + " " + Build.VERSION.SDK_INT + ")"; String build = Build.DISPLAY; // Select the substring that begins after `Chrome/` and goes until the next ` `. String webView = userAgentString.substring(userAgentString.indexOf("Chrome/") + 7, userAgentString.indexOf(" ", userAgentString.indexOf("Chrome/"))); @@ -199,21 +205,19 @@ public class AboutTabFragment extends Fragment { SpannableStringBuilder androidStringBuilder = new SpannableStringBuilder(androidLabel + android); SpannableStringBuilder buildStringBuilder = new SpannableStringBuilder(buildLabel + build); SpannableStringBuilder webViewStringBuilder = new SpannableStringBuilder(webViewLabel + webView); - SpannableStringBuilder easyListStringBuilder = new SpannableStringBuilder(easyListLabel + MainWebViewActivity.easyListVersion); - SpannableStringBuilder easyPrivacyStringBuilder = new SpannableStringBuilder(easyPrivacyLabel + MainWebViewActivity.easyPrivacyVersion); - SpannableStringBuilder fanboyAnnoyanceStringBuilder = new SpannableStringBuilder(fanboyAnnoyanceLabel + MainWebViewActivity.fanboysAnnoyanceVersion); - SpannableStringBuilder fanboySocialStringBuilder = new SpannableStringBuilder(fanboySocialLabel + MainWebViewActivity.fanboysSocialVersion); - SpannableStringBuilder ultraPrivacyStringBuilder = new SpannableStringBuilder(ultraPrivacyLabel + MainWebViewActivity.ultraPrivacyVersion); + SpannableStringBuilder easyListStringBuilder = new SpannableStringBuilder(easyListLabel + blocklistVersions[0]); + SpannableStringBuilder easyPrivacyStringBuilder = new SpannableStringBuilder(easyPrivacyLabel + blocklistVersions[1]); + SpannableStringBuilder fanboyAnnoyanceStringBuilder = new SpannableStringBuilder(fanboyAnnoyanceLabel + blocklistVersions[2]); + SpannableStringBuilder fanboySocialStringBuilder = new SpannableStringBuilder(fanboySocialLabel + blocklistVersions[3]); + SpannableStringBuilder ultraPrivacyStringBuilder = new SpannableStringBuilder(ultraPrivacyLabel + blocklistVersions[4]); // Create the `blueColorSpan` variable. ForegroundColorSpan blueColorSpan; // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23. if (darkTheme) { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400)); } else { - //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700)); } @@ -356,7 +360,6 @@ public class AboutTabFragment extends Fragment { // Load the tabs according to the theme. if (darkTheme) { // The dark theme is applied. // Set the background color. The deprecated `.getColor()` must be used until the minimum API >= 23. - //noinspection deprecation tabWebView.setBackgroundColor(getResources().getColor(R.color.gray_850)); switch (tabNumber) { diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java index 7ef26d6e..cf1e56ce 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java +++ b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java @@ -25,6 +25,8 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.MotionEvent; +import android.webkit.HttpAuthHandler; +import android.webkit.SslErrorHandler; import android.webkit.WebView; import androidx.annotation.NonNull; @@ -52,6 +54,10 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild // Keep a copy of the WebView fragment ID. private long webViewFragmentId; + // Store the handlers. + private SslErrorHandler sslErrorHandler; + private HttpAuthHandler httpAuthHandler; + // Track if domain settings are applied to this nested scroll WebView and, if so, the database ID. private boolean domainSettingsApplied; private int domainSettingsDatabaseId; @@ -62,6 +68,9 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild // Track the status of first-party cookies. private boolean acceptFirstPartyCookies; + // Track the domain settings JavaScript status. This can be removed once night mode does not require JavaScript. + private boolean domainSettingsJavaScriptEnabled; + // Track the resource requests. private ArrayList resourceRequests = new ArrayList<>(); private boolean easyListEnabled; @@ -100,8 +109,11 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild // The ignore pinned domain information tracker. This is set when a user proceeds past a pinned mismatch dialog to prevent the dialog from showing again until after the domain changes. private boolean ignorePinnedDomainInformation; + // Track navigation of history. + private boolean navigatingHistory; + // The default or favorite icon. - Bitmap favoriteOrDefaultIcon; + private Bitmap favoriteOrDefaultIcon; // Track night mode. private boolean nightMode; @@ -155,6 +167,40 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild } + // SSL error handler. + public void setSslErrorHandler(SslErrorHandler sslErrorHandler) { + // Store the current SSL error handler. + this.sslErrorHandler = sslErrorHandler; + } + + public SslErrorHandler getSslErrorHandler() { + // Return the current SSL error handler. + return sslErrorHandler; + } + + public void resetSslErrorHandler() { + // Reset the current SSL error handler. + sslErrorHandler = null; + } + + + // HTTP authentication handler. + public void setHttpAuthHandler(HttpAuthHandler httpAuthHandler) { + // Store the current HTTP authentication handler. + this.httpAuthHandler = httpAuthHandler; + } + + public HttpAuthHandler getHttpAuthHandler() { + // Return the current HTTP authentication handler. + return httpAuthHandler; + } + + public void resetHttpAuthHandler() { + // Reset the current HTTP authentication handler. + httpAuthHandler = null; + } + + // Domain settings. public void setDomainSettingsApplied(boolean applied) { // Store the domain settings applied status. @@ -208,6 +254,18 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild } + // Domain settings JavaScript enabled. This can be removed once night mode does not require JavaScript. + public void setDomainSettingsJavaScriptEnabled(boolean status) { + // Store the domain settings JavaScript status. + domainSettingsJavaScriptEnabled = status; + } + + public boolean getDomainSettingsJavaScriptEnabled() { + // Return the domain settings JavaScript status. + return domainSettingsJavaScriptEnabled; + } + + // Resource requests. public void addResourceRequest(String[] resourceRequest) { // Add the resource request to the list. @@ -496,16 +554,29 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild } - // Ignore pinned information. The syntax looks better as written, even if it is always inverted. + // Ignore pinned information. + public void setIgnorePinnedDomainInformation(boolean status) { + // Set the status of the ignore pinned domain information tracker. + ignorePinnedDomainInformation = status; + } + + // The syntax looks better as written, even if it is always inverted. @SuppressWarnings("BooleanMethodIsAlwaysInverted") public boolean ignorePinnedDomainInformation() { // Return the status of the ignore pinned domain information tracker. return ignorePinnedDomainInformation; } - public void setIgnorePinnedDomainInformation(boolean status) { - // Set the status of the ignore pinned domain information tracker. - ignorePinnedDomainInformation = status; + + // Navigating history. + public void setNavigatingHistory(boolean status) { + // Set the status of navigating history. + navigatingHistory = status; + } + + public boolean getNavigatingHistory() { + // Return the status of navigating history. + return navigatingHistory; } diff --git a/app/src/main/res/layout/main_framelayout.xml b/app/src/main/res/layout/main_framelayout.xml index a1e0e094..3057c922 100644 --- a/app/src/main/res/layout/main_framelayout.xml +++ b/app/src/main/res/layout/main_framelayout.xml @@ -77,6 +77,7 @@ android:id="@+id/tablayout" android:layout_height="wrap_content" android:layout_width="wrap_content" + app:tabIndicatorGravity="top" app:tabMode="scrollable" /> diff --git a/app/src/main/res/layout/webview_framelayout.xml b/app/src/main/res/layout/webview_framelayout.xml index bb6de103..27e62773 100644 --- a/app/src/main/res/layout/webview_framelayout.xml +++ b/app/src/main/res/layout/webview_framelayout.xml @@ -41,7 +41,7 @@ android:layout_height="3dp" android:layout_width="match_parent" android:max="100" - android:progressTint="@color/yellow_a700" + android:progressTint="?attr/progressTintColor" android:progressBackgroundTint="@color/transparent" android:visibility="gone" tools:ignore="UnusedAttribute" /> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 32938c30..c7ec1353 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -50,6 +50,8 @@ Kein Titel Unbekannte URL: Öffnen mit + Neuer Tab + Tab hinzufügen Speichern Unter @@ -110,6 +112,7 @@ Navigationspanel Navigation + Tab schließen Leeren und verlassen Startseite Zurück @@ -176,6 +179,7 @@ Stop + In neuem Tab öffnen URL kopieren Download URL E-Mail-Adresse @@ -413,6 +417,10 @@ JavaScript standardmäßig aktivieren JavaScript ermöglicht es Websites, Programme (Scripts) auf Ihrem Gerät auszuführen. Erstanbieter-Cookies standardmäßig aktivieren + Da die Cookie-Einstellungen App-weit gelten, werden, wenn im aktiven Tab Cookies erlaubt sind, + auch in den Hintergrund-Tabs Cookies der dort angezeigten Seiten und deren Domains angenommen. + Unter Android KitKat (version 4.4.x) wird nicht zwischen Cookies und Drittanbieter-Cookies unterschieden, + sodass in dieser Version mit dieser Einstellung beide Cookie-Varianten aktiviert werden. Drittanbieter-Cookies standardmäßig aktivieren Diese Option benötigt Android Lollipop (Version 5.0) oder höher. Sie hat keine Auswirkungen, wenn Erstanbieter-Cookies deaktiviert sind. DOM-Speicher standardmäßig aktivieren diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index b6ec37b8..869a7ac2 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -46,6 +46,8 @@ Nessun titolo URL non riconosciuta: Apri con + Nuova Scheda + Aggiungi Scheda Salva come @@ -107,6 +109,7 @@ Menù di navigazione Navigazione + Chiudi Scheda Elimina dati ed esci Home Indietro @@ -173,6 +176,7 @@ Stop + Apri in una nuova Scheda Copia URL Scarica URL Indirizzo Email @@ -412,6 +416,9 @@ Abilita JavaScript Permetti a JavaScript di eseguire programmi (script) sul dispositivo. Abilita cookies proprietari + Dal momento che i cookie proprietari sono un\'impostazione a livello di applicazione, + quando la scheda attiva ha i cookie proprietari attivati anche ogni richiesta di rete in background da parte delle altre schede includerà i cookie per i relativi domini. + Android KitKat (versione 4.4.x) inoltre non distingue tra cookie proprietari e cookie di terze parti e pertanto li abiliterà entrambi con questa impostazione. Abilita cookies di terze parti Questa impostazione richiede Android Lollipop (version 5.0) o successivo. Non ha effetti se i cookies proprietari sono disabilitati. Abilita DOM Storage diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index c4130307..e1d1f13e 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -44,6 +44,8 @@ Başlıksız Onaylanmayan URL: Bununla aç + Yeni Sekme + Sekme Ekle Farklı Kaydet @@ -104,6 +106,7 @@ Açılır Menü Gezinti + Sekmeyi Kapa Temizle ve Çık Anasayfa Geri @@ -170,6 +173,7 @@ Dur + Yeni Sekmede Aç URL Kopyala URL İndir Eposta Adresi @@ -406,6 +410,9 @@ JavaScript\'i varsayılan olarak etkinleştir JavaScript web sitelerin cihazdaki programları(scriptler) çalıştırmasına izin verir. Birinci taraf çerezleri varsayılan olarak etkinleştir + Birinci taraf çerezleri uygulama düzeyinde bir ayar olduğundan, aktif sekmede çerezler etkinleştirildiğinde, + arka plandaki diğer sekmeler tarafından yapılan herhangi ağ istekleri, domainler için kayıtlı çerezleri de içerecektir. + Android KitKat (sürüm 4.4.x), birinci ve üçüncü taraf çerezleri arasında ayrım yapmaz ve bu ayarda ikisini de etkinleştirir. Üçüncü taraf çerezleri varsayılan olarak etkinleştir Bu ayarı etkinleştirmek için Android Lollipop sürümüne(5.0) ya da daha üst sürümlere sahip olmak gerekir. Birinci taraf çerezler devre dışı olduğu takdirde etkisi yoktur. diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index daa5deb6..63641a11 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -23,10 +23,12 @@ @@ -124,6 +125,7 @@ diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 3eaac49f..e0e767e3 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -47,6 +47,7 @@ + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 643cee3f..26e0c893 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -23,10 +23,12 @@ @@ -122,6 +123,7 @@ diff --git a/build.gradle b/build.gradle index b4b80490..3832dcd8 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.4.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fd0f4afd..ed71cde0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Jan 15 11:00:04 MST 2019 +#Wed Apr 17 14:57:58 MST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip -- 2.45.2