X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FMainWebViewActivity.java;h=e39b54a440a9d54534f070a082d8327cad9afe4b;hp=e6ec1b71cebebd8dc39c490b79c1ba37d50cb656;hb=fe788514a50a591f9722ededc13e608ceb268bb8;hpb=3d167d1ec7d0cef1ef032f20859bb0de8ddb01cf 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 e6ec1b71..e39b54a4 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -36,7 +36,6 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -133,6 +132,7 @@ import com.stoutner.privacybrowser.fragments.WebViewTabFragment; import com.stoutner.privacybrowser.helpers.AdHelper; import com.stoutner.privacybrowser.helpers.BlockListHelper; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; +import com.stoutner.privacybrowser.helpers.CheckPinnedMismatchHelper; import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper; import com.stoutner.privacybrowser.helpers.OrbotProxyHelper; import com.stoutner.privacybrowser.views.NestedScrollWebView; @@ -154,6 +154,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +// TODO. The swipe refresh indicator needs to be enabled/disabled when switching 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, @@ -174,30 +176,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `favoriteIconDefaultBitmap` public static so it can be accessed from `PinnedMismatchDialog`. It is also used in `onCreate()` and `applyDomainSettings`. public static Bitmap favoriteIconDefaultBitmap; + // TODO Remove. // `formattedUrlString` is public static so it can be accessed from `AddDomainDialog`, `BookmarksActivity`, `DomainSettingsFragment`, and `PinnedMismatchDialog`. // It is also used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onCreateHomeScreenShortcutCreate()`, `loadUrlFromTextBox()`, and `applyProxyThroughOrbot()`. public static String formattedUrlString; - // `sslCertificate` is public static so it can be accessed from `DomainsActivity`, `DomainsListFragment`, `DomainSettingsFragment`, `PinnedMismatchDialog`, and `ViewSslCertificateDialog`. - // It is also used in `onCreate()` and `checkPinnedMismatch()`. - public static SslCertificate sslCertificate; - - // `currentHostIpAddresses` is public static so it can be accessed from `DomainSettingsFragment`, `GetHostIpAddresses()`, and `ViewSslCertificateDialog`. - // It is also used in `onCreate()` and `GetHostIpAddresses()`. - public static String currentHostIpAddresses; - - // The getting IP addresses tracker is used in `onCreate() and `GetHostIpAddresses`. - public static boolean gettingIpAddresses; - - // The URL loading tracker is public static so it can be accessed from `GetHostIpAddresses`. - // It is also used in `onCreate()`, `onCreateOptionsMenu()`, `loadUrl()`, `applyDomainSettings()`, and `GetHostIpAddresses`. - public static boolean urlIsLoading; - // `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. public static String orbotStatus; - // `appliedUserAgentString` is public static so it can be accessed from `ViewSourceActivity`. It is also used in `applyDomainSettings()`. - public static String appliedUserAgentString; + // The WebView pager adapter is accessed from `PinnedMismatchDialog`. 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 also used in `onRestart()` public static boolean reloadOnRestart; @@ -215,25 +203,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook public static String fanboysSocialVersion; public static String ultraPrivacyVersion; - // `blockAllThirdPartyRequests` is public static so it can be accessed from `RequestsActivity`. - // It is also used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyAppSettings()` - public static boolean blockAllThirdPartyRequests; - // `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; - // The pinned variables are public static so they can be accessed from `PinnedMismatchDialog`. They are also used in `onCreate()`, `applyDomainSettings()`, and `checkPinnedMismatch()`. - public static String pinnedSslIssuedToCName; - public static String pinnedSslIssuedToOName; - public static String pinnedSslIssuedToUName; - public static String pinnedSslIssuedByCName; - public static String pinnedSslIssuedByOName; - public static String pinnedSslIssuedByUName; - public static Date pinnedSslStartDate; - public static Date pinnedSslEndDate; - public static String pinnedHostIpAddresses; - // The user agent constants are public static so they can be accessed from `SettingsFragment`, `DomainsActivity`, and `DomainSettingsFragment`. public final static int UNRECOGNIZED_USER_AGENT = -1; public final static int SETTINGS_WEBVIEW_DEFAULT_USER_AGENT = 1; @@ -244,22 +217,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook - // `pinnedDomainSslCertificate` is used in `onCreate()`, `applyDomainSettings()`, and `checkPinnedMismatch()`. - private static boolean pinnedSslCertificate; - - // `pinnedIpAddress` is used in `applyDomainSettings()` and `checkPinnedMismatch()`. - private static boolean pinnedIpAddresses; - - // `ignorePinnedDomainInformation` is used in `onSslMismatchProceed()`, `applyDomainSettings()`, and `checkPinnedMismatch()`. - private static boolean ignorePinnedDomainInformation; - - // The fragment manager is initialized in `onCreate()` and accessed from the static `checkPinnedMismatch()`. - private static FragmentManager fragmentManager; - - - // A handle for the activity is set in `onCreate()` and accessed in `WebViewPagerAdapter`. - private Activity activity; - // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, `onSslMismatchBack()`, and `applyDomainSettings()`. private boolean navigatingHistory; @@ -276,21 +233,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `customHeader` is used in `onCreate()`, `onOptionsItemSelected()`, `onCreateContextMenu()`, and `loadUrl()`. private final Map customHeaders = new HashMap<>(); - // `javaScriptEnabled` is also used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `applyDomainSettings()`, and `updatePrivacyIcons()`. - private boolean javaScriptEnabled; - // `firstPartyCookiesEnabled` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onDownloadImage()`, `onDownloadFile()`, and `applyDomainSettings()`. private boolean firstPartyCookiesEnabled; - // `thirdPartyCookiesEnabled` used in `onCreate()`, `onPrepareOptionsMenu()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. - private boolean thirdPartyCookiesEnabled; - - // `domStorageEnabled` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. - private boolean domStorageEnabled; - // `saveFormDataEnabled` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. It can be removed once the minimum API >= 26. private boolean saveFormDataEnabled; + // TODO Move to NestedScrollWebView. // `nightMode` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. private boolean nightMode; @@ -300,20 +249,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `searchURL` is used in `loadURLFromTextBox()` and `applyProxyThroughOrbot()`. private String searchURL; - // `mainMenu` is used in `onCreateOptionsMenu()` and `updatePrivacyIcons()`. - private Menu mainMenu; + // The options menu is set in `onCreateOptionsMenu()` and used in `onOptionsItemSelected()` and `updatePrivacyIcons()`. + private Menu optionsMenu; - // `refreshMenuItem` is used in `onCreate()` and `onCreateOptionsMenu()`. + // The refresh menu item is set in `onCreateOptionsMenu()` and accessed from `initializeWebView()`. + // It must be this way because `initializeWebView()` runs before the menu is created but doesn't actually modify the menu until later. private MenuItem refreshMenuItem; - // The WebView pager adapter is used in `onCreate()`, `onResume()`, and `addTab()`. - private WebViewPagerAdapter webViewPagerAdapter; - // The navigation requests menu item is used in `onCreate()` and accessed from `WebViewPagerAdapter`. - private MenuItem navigationRequestsMenuItem; + private MenuItem navigationRequestsMenuItem; // TODO. + // TODO. This could probably be removed. // The blocklist helper is used in `onCreate()` and `WebViewPagerAdapter`. - BlockListHelper blockListHelper; + private BlockListHelper blockListHelper; // The blocklists are populated in `onCreate()` and accessed from `WebViewPagerAdapter`. private ArrayList> easyList; @@ -322,7 +270,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private ArrayList> fanboysSocialList; private ArrayList> ultraPrivacy; - // The blocklist menu items are used in `onCreate()`, `onCreateOptionsMenu()`, and `onPrepareOptionsMenu()`. + // The blocklist menu items are used in `onCreateOptionsMenu()`, `onPrepareOptionsMenu()`, and `initializeWebView()`. private MenuItem blocklistsMenuItem; private MenuItem easyListMenuItem; private MenuItem easyPrivacyMenuItem; @@ -331,19 +279,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private MenuItem ultraPrivacyMenuItem; private MenuItem blockAllThirdPartyRequestsMenuItem; - // The blocklist variables are used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyAppSettings()`. - private boolean easyListEnabled; - private boolean easyPrivacyEnabled; - private boolean fanboysAnnoyanceListEnabled; - private boolean fanboysSocialBlockingListEnabled; - private boolean ultraPrivacyEnabled; - // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`. private String webViewDefaultUserAgent; - // `defaultCustomUserAgentString` is used in `onPrepareOptionsMenu()` and `applyDomainSettings()`. - private String defaultCustomUserAgentString; - // `privacyBrowserRuntime` is used in `onCreate()`, `onOptionsItemSelected()`, and `applyAppSettings()`. private Runtime privacyBrowserRuntime; @@ -374,9 +312,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `downloadWithExternalApp` is used in `onCreate()`, `onCreateContextMenu()`, and `applyDomainSettings()`. private boolean downloadWithExternalApp; - // `currentDomainName` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onAddDomain()`, and `applyDomainSettings()`. - private String currentDomainName; - // `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`. private BroadcastReceiver orbotStatusBroadcastReceiver; @@ -459,11 +394,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private final int DOWNLOAD_IMAGE_REQUEST_CODE = 2; @Override - // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled. The whole premise of Privacy Browser is built around an understanding of these dangers. - // Also, remove the warning about needing to override `performClick()` when using an `OnTouchListener` with `WebView`. - @SuppressLint({"SetJavaScriptEnabled", "ClickableViewAccessibility"}) - // Remove Android Studio's warning about deprecations. The deprecated `getColor()` must be used until API >= 23. - @SuppressWarnings("deprecation") + // Remove the warning about needing to override `performClick()` when using an `OnTouchListener` with `WebView`. + @SuppressLint("ClickableViewAccessibility") protected void onCreate(Bundle savedInstanceState) { // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); @@ -490,10 +422,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the content view. setContentView(R.layout.main_framelayout); - // Get handles for views, resources, and managers. - activity = this; - Resources resources = getResources(); - fragmentManager = getSupportFragmentManager(); + // Get handles for the input method manager and toolbar. inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); Toolbar toolbar = findViewById(R.id.toolbar); @@ -509,11 +438,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); // Initialize the foreground color spans for highlighting the URLs. We have to use the deprecated `getColor()` until API >= 23. - redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700)); - initialGrayColorSpan = new ForegroundColorSpan(resources.getColor(R.color.gray_500)); - finalGrayColorSpan = new ForegroundColorSpan(resources.getColor(R.color.gray_500)); + redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700)); + initialGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500)); + finalGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500)); - // Get a handle for `urlTextBox`. + // Get handles for the URL views. + RelativeLayout urlRelativeLayout = findViewById(R.id.url_relativelayout); EditText urlEditText = findViewById(R.id.url_edittext); // Remove the formatting from `urlTextBar` when the user is editing the text. @@ -550,8 +480,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set `waitingForOrbotHTMLString`. waitingForOrbotHtmlString = "

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

"; - // Initialize `currentDomainName`, `orbotStatus`, and `waitingForOrbot`. - currentDomainName = ""; + // Initialize the Orbot status and the waiting for Orbot trackers. orbotStatus = "unknown"; waitingForOrbot = false; @@ -619,7 +548,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook navigationRequestsMenuItem = navigationMenu.getItem(6); // Initialize the web view pager adapter. - webViewPagerAdapter = new WebViewPagerAdapter(fragmentManager); + webViewPagerAdapter = new WebViewPagerAdapter(getSupportFragmentManager()); // Set the pager adapter on the web view pager. webViewPager.setAdapter(webViewPagerAdapter); @@ -648,6 +577,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Store the current WebView. currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + // Update the privacy icons. `true` redraws the icons in the app bar. + updatePrivacyIcons(true); + // Store the current formatted URL string. formattedUrlString = currentWebView.getUrl(); @@ -665,14 +597,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the background to indicate the domain settings status. if (currentWebView.getDomainSettingsApplied()) { - // Set a green background on `urlTextBox` to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + // 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) { - urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); } else { - urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); } } else { - urlEditText.setBackgroundDrawable(getResources().getDrawable(R.color.transparent)); + urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent)); } // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled via swiping in the view pager. @@ -710,27 +642,28 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override public void onTabReselected(TabLayout.Tab tab) { // Instantiate the View SSL Certificate dialog. - DialogFragment viewSslCertificateDialogFragment = new ViewSslCertificateDialog(); + DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId()); // Display the View SSL Certificate dialog. viewSslCertificateDialogFragment.show(getSupportFragmentManager(), getString(R.string.view_ssl_certificate)); } }); - // Add the first tab. (It doesn't matter what view is passed. That is just required as part of the ImageView `onClick()` syntax). - addTab(webViewPager); + // Add the first tab. + addTab(null); // Set the bookmarks drawer resources according to the theme. This can't be done in the layout due to compatibility issues with the `DrawerLayout` support widget. + // The deprecated `getResources().getDrawable()` must be used until the minimum API >= 21 and and `getResources().getColor()` must be used until the minimum API >= 23. if (darkTheme) { - launchBookmarksActivityFab.setImageDrawable(resources.getDrawable(R.drawable.bookmarks_dark)); - createBookmarkFolderFab.setImageDrawable(resources.getDrawable(R.drawable.create_folder_dark)); - createBookmarkFab.setImageDrawable(resources.getDrawable(R.drawable.create_bookmark_dark)); - bookmarksListView.setBackgroundColor(resources.getColor(R.color.gray_850)); + launchBookmarksActivityFab.setImageDrawable(getResources().getDrawable(R.drawable.bookmarks_dark)); + createBookmarkFolderFab.setImageDrawable(getResources().getDrawable(R.drawable.create_folder_dark)); + createBookmarkFab.setImageDrawable(getResources().getDrawable(R.drawable.create_bookmark_dark)); + bookmarksListView.setBackgroundColor(getResources().getColor(R.color.gray_850)); } else { - launchBookmarksActivityFab.setImageDrawable(resources.getDrawable(R.drawable.bookmarks_light)); - createBookmarkFolderFab.setImageDrawable(resources.getDrawable(R.drawable.create_folder_light)); - createBookmarkFab.setImageDrawable(resources.getDrawable(R.drawable.create_bookmark_light)); - bookmarksListView.setBackgroundColor(resources.getColor(R.color.white)); + launchBookmarksActivityFab.setImageDrawable(getResources().getDrawable(R.drawable.bookmarks_light)); + createBookmarkFolderFab.setImageDrawable(getResources().getDrawable(R.drawable.create_folder_light)); + createBookmarkFab.setImageDrawable(getResources().getDrawable(R.drawable.create_bookmark_light)); + bookmarksListView.setBackgroundColor(getResources().getColor(R.color.white)); } // Set the launch bookmarks activity FAB to launch the bookmarks activity. @@ -753,7 +686,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook createBookmarkFolderFab.setOnClickListener(v -> { // Show the create bookmark folder dialog and name the instance `@string/create_folder`. DialogFragment createBookmarkFolderDialog = new CreateBookmarkFolderDialog(); - createBookmarkFolderDialog.show(fragmentManager, resources.getString(R.string.create_folder)); + createBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.create_folder)); }); // Set the create new bookmark FAB to display an alert dialog. @@ -762,7 +695,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebView.getUrl(), currentWebView.getTitle(), favoriteIconBitmap); // Display the create bookmark dialog. - createBookmarkDialog.show(fragmentManager, resources.getString(R.string.create_bookmark)); + createBookmarkDialog.show(getSupportFragmentManager(), getString(R.string.create_bookmark)); }); // Search for the string on the page whenever a character changes in the `findOnPageEditText`. @@ -865,11 +798,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Show the edit bookmark folder `AlertDialog` and name the instance `@string/edit_folder`. DialogFragment editBookmarkFolderDialog = EditBookmarkFolderDialog.folderDatabaseId(databaseId); - editBookmarkFolderDialog.show(fragmentManager, resources.getString(R.string.edit_folder)); + editBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.edit_folder)); } else { // Show the edit bookmark `AlertDialog` and name the instance `@string/edit_bookmark`. DialogFragment editBookmarkDialog = EditBookmarkDialog.bookmarkDatabaseId(databaseId); - editBookmarkDialog.show(fragmentManager, resources.getString(R.string.edit_bookmark)); + editBookmarkDialog.show(getSupportFragmentManager(), getString(R.string.edit_bookmark)); } // Consume the event. @@ -877,11 +810,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook }); // Get the status bar pixel size. - int statusBarResourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); - int statusBarPixelSize = resources.getDimensionPixelSize(statusBarResourceId); + int statusBarResourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); + int statusBarPixelSize = getResources().getDimensionPixelSize(statusBarResourceId); // Get the resource density. - float screenDensity = resources.getDisplayMetrics().density; + float screenDensity = getResources().getDisplayMetrics().density; // Calculate the drawer header padding. This is used to move the text in the drawer headers below any cutouts. drawerHeaderPaddingLeftAndRight = (int) (15 * screenDensity); @@ -959,10 +892,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook inFullScreenBrowsingMode = false; // Initialize the privacy settings variables. - javaScriptEnabled = false; firstPartyCookiesEnabled = false; - thirdPartyCookiesEnabled = false; - domStorageEnabled = false; saveFormDataEnabled = false; // Form data can be removed once the minimum API >= 26. nightMode = false; @@ -991,7 +921,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Initialize the user agent array adapter and string array. userAgentNamesArray = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.spinner_item); - userAgentDataArray = resources.getStringArray(R.array.user_agent_data); + userAgentDataArray = getResources().getStringArray(R.array.user_agent_data); // Get the intent that started the app. Intent launchingIntent = getIntent(); @@ -1022,6 +952,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override protected void onNewIntent(Intent intent) { + // Add a new tab. + addTab(null); + // Sets the new intent as the activity intent, so that any future `getIntent()`s pick up this one instead of creating a new activity. setIntent(intent); @@ -1085,7 +1018,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook sendBroadcast(orbotIntent); } - // Apply the app settings if returning from the Settings activity.. + // Apply the app settings if returning from the Settings activity. if (reapplyAppSettingsOnRestart) { // Apply the app settings. applyAppSettings(); @@ -1105,8 +1038,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the nested scroll WebView from the tab fragment. NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); - // TODO this doesn't seem to work if for WebViews that aren't visible. - // Reload the WebView. + // Reload the WebView. This doesn't seem to work if for WebViews that aren't visible. nestedScrollWebView.reload(); } } @@ -1119,10 +1051,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook reapplyAppSettingsOnRestart = false; } + // TODO apply to all the tabs. // Apply the domain settings if returning from the Domains activity. if (reapplyDomainSettingsOnRestart) { // Reapply the domain settings. - applyDomainSettings(formattedUrlString, false, true); + applyDomainSettings(currentWebView, formattedUrlString, false, true); // Reset `reapplyDomainSettingsOnRestart`. reapplyDomainSettingsOnRestart = false; @@ -1262,8 +1195,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Inflate the menu. This adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.webview_options_menu, menu); - // Set mainMenu so it can be used by `onOptionsItemSelected()` and `updatePrivacyIcons`. - mainMenu = menu; + // Store a handle for the options menu so it can be used by `onOptionsItemSelected()` and `updatePrivacyIcons`. + optionsMenu = menu; // Set the initial status of the privacy icons. `false` does not call `invalidateOptionsMenu` as the last step. updatePrivacyIcons(false); @@ -1312,7 +1245,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Replace Refresh with Stop if a URL is already loading. - if (urlIsLoading) { + if (currentWebView != null && currentWebView.getProgress() != 100) { // Set the title. refreshMenuItem.setTitle(R.string.stop); @@ -1369,40 +1302,44 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the current font size from the fontSize = currentWebView.getSettings().getTextZoom(); - // Set the status of the display images menu item. + // Set the status of the menu item checkboxes. + toggleDomStorageMenuItem.setChecked(currentWebView.getSettings().getDomStorageEnabled()); + easyListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)); + easyPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)); + fanboysAnnoyanceListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)); + fanboysSocialBlockingListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST)); + ultraPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)); + blockAllThirdPartyRequestsMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)); displayImagesMenuItem.setChecked(currentWebView.getSettings().getLoadsImagesAutomatically()); // Initialize the display names for the blocklists with the number of blocked requests. blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + currentWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - easyListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASY_LIST_BLOCKED_REQUESTS) + " - " + getString(R.string.easylist)); - easyPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY_BLOCKED_REQUESTS) + " - " + getString(R.string.easyprivacy)); - fanboysAnnoyanceListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS) + " - " + getString(R.string.fanboys_annoyance_list)); - fanboysSocialBlockingListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS) + " - " + - getString(R.string.fanboys_social_blocking_list)); - ultraPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY_BLOCKED_REQUESTS) + " - " + getString(R.string.ultraprivacy)); - blockAllThirdPartyRequestsMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_BLOCKED_REQUESTS) + " - " + getString(R.string.block_all_third_party_requests)); + easyListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASY_LIST) + " - " + getString(R.string.easylist)); + easyPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY) + " - " + getString(R.string.easyprivacy)); + fanboysAnnoyanceListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST) + " - " + getString(R.string.fanboys_annoyance_list)); + fanboysSocialBlockingListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST) + " - " + getString(R.string.fanboys_social_blocking_list)); + ultraPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY) + " - " + getString(R.string.ultraprivacy)); + blockAllThirdPartyRequestsMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS) + " - " + getString(R.string.block_all_third_party_requests)); } // Set the status of the menu item checkboxes. toggleFirstPartyCookiesMenuItem.setChecked(firstPartyCookiesEnabled); - toggleThirdPartyCookiesMenuItem.setChecked(thirdPartyCookiesEnabled); - toggleDomStorageMenuItem.setChecked(domStorageEnabled); toggleSaveFormDataMenuItem.setChecked(saveFormDataEnabled); // Form data can be removed once the minimum API >= 26. - easyListMenuItem.setChecked(easyListEnabled); - easyPrivacyMenuItem.setChecked(easyPrivacyEnabled); - fanboysAnnoyanceListMenuItem.setChecked(fanboysAnnoyanceListEnabled); - fanboysSocialBlockingListMenuItem.setChecked(fanboysSocialBlockingListEnabled); - ultraPrivacyMenuItem.setChecked(ultraPrivacyEnabled); - blockAllThirdPartyRequestsMenuItem.setChecked(blockAllThirdPartyRequests); swipeToRefreshMenuItem.setChecked(swipeRefreshLayout.isEnabled()); nightModeMenuItem.setChecked(nightMode); proxyThroughOrbotMenuItem.setChecked(proxyThroughOrbot); - // Enable third-party cookies if first-party cookies are enabled. - toggleThirdPartyCookiesMenuItem.setEnabled(firstPartyCookiesEnabled); + // Only modify third-party cookies if the API >= 21. + if (Build.VERSION.SDK_INT >= 21) { + // Set the status of the third-party cookies checkbox. + toggleThirdPartyCookiesMenuItem.setChecked(cookieManager.acceptThirdPartyCookies(currentWebView)); + + // Enable third-party cookies if first-party cookies are enabled. + toggleThirdPartyCookiesMenuItem.setEnabled(firstPartyCookiesEnabled); + } // Enable DOM Storage if JavaScript is enabled. - toggleDomStorageMenuItem.setEnabled(javaScriptEnabled); + toggleDomStorageMenuItem.setEnabled(currentWebView.getSettings().getJavaScriptEnabled()); // Enable Clear Cookies if there are any. clearCookiesMenuItem.setEnabled(cookieManager.hasCookies()); @@ -1436,8 +1373,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Enable Clear Data if any of the submenu items are enabled. clearDataMenuItem.setEnabled(clearCookiesMenuItem.isEnabled() || clearDOMStorageMenuItem.isEnabled() || clearFormDataMenuItem.isEnabled()); - // Disable Fanboy's Social Blocking List if Fanboy's Annoyance List is checked. - fanboysSocialBlockingListMenuItem.setEnabled(!fanboysAnnoyanceListEnabled); + // Disable Fanboy's Social Blocking List menu item if Fanboy's Annoyance List is checked. + fanboysSocialBlockingListMenuItem.setEnabled(!fanboysAnnoyanceListMenuItem.isChecked()); // Select the current user agent menu item. A switch statement cannot be used because the user agents are not compile time constants. if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[0])) { // Privacy Browser. @@ -1557,20 +1494,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the selected menu item ID. int menuItemId = menuItem.getItemId(); + // Get a handle for the shared preferences. + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + // Run the commands that correlate to the selected menu item. switch (menuItemId) { case R.id.toggle_javascript: - // Switch the status of javaScriptEnabled. - javaScriptEnabled = !javaScriptEnabled; - - // Apply the new JavaScript status. - currentWebView.getSettings().setJavaScriptEnabled(javaScriptEnabled); + // Toggle the JavaScript status. + currentWebView.getSettings().setJavaScriptEnabled(!currentWebView.getSettings().getJavaScriptEnabled()); // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. updatePrivacyIcons(true); // Display a `Snackbar`. - if (javaScriptEnabled) { // JavaScrip is enabled. + if (currentWebView.getSettings().getJavaScriptEnabled()) { // JavaScrip is enabled. Snackbar.make(findViewById(R.id.webviewpager), R.string.javascript_enabled, Snackbar.LENGTH_SHORT).show(); } else if (firstPartyCookiesEnabled) { // JavaScript is disabled, but first-party cookies are enabled. Snackbar.make(findViewById(R.id.webviewpager), R.string.javascript_disabled, Snackbar.LENGTH_SHORT).show(); @@ -1586,21 +1523,26 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook if (currentWebView.getDomainSettingsApplied()) { // Edit the current domain settings. // Reapply the domain settings on returning to `MainWebViewActivity`. reapplyDomainSettingsOnRestart = true; - currentDomainName = ""; + currentWebView.resetCurrentDomainName(); + + // TODO. Move these to `putExtra`. The certificate can be stored as strings. + // Store the current SSL certificate and IP addresses in the domains activity. + DomainsActivity.currentSslCertificate = currentWebView.getCertificate(); + DomainsActivity.currentIpAddresses = currentWebView.getCurrentIpAddresses(); // Create an intent to launch the domains activity. Intent domainsIntent = new Intent(this, DomainsActivity.class); // Put extra information instructing the domains activity to directly load the current domain and close on back instead of returning to the domains list. - domainsIntent.putExtra("loadDomain", currentWebView.getDomainSettingsDatabaseId()); - domainsIntent.putExtra("closeOnBack", true); + domainsIntent.putExtra("load_domain", currentWebView.getDomainSettingsDatabaseId()); + domainsIntent.putExtra("close_on_back", true); // Make it so. startActivity(domainsIntent); } else { // Add a new domain. // Apply the new domain settings on returning to `MainWebViewActivity`. reapplyDomainSettingsOnRestart = true; - currentDomainName = ""; + currentWebView.resetCurrentDomainName(); // Get the current domain Uri currentUri = Uri.parse(formattedUrlString); @@ -1612,12 +1554,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Create the domain and store the database ID. int newDomainDatabaseId = domainsDatabaseHelper.addDomain(currentDomain); + // TODO. Move these to `putExtra`. The certificate can be stored as strings. + // Store the current SSL certificate and IP addresses in the domains activity. + DomainsActivity.currentSslCertificate = currentWebView.getCertificate(); + DomainsActivity.currentIpAddresses = currentWebView.getCurrentIpAddresses(); + // Create an intent to launch the domains activity. Intent domainsIntent = new Intent(this, DomainsActivity.class); // Put extra information instructing the domains activity to directly load the new domain and close on back instead of returning to the domains list. - domainsIntent.putExtra("loadDomain", newDomainDatabaseId); - domainsIntent.putExtra("closeOnBack", true); + domainsIntent.putExtra("load_domain", newDomainDatabaseId); + domainsIntent.putExtra("close_on_back", true); // Make it so. startActivity(domainsIntent); @@ -1640,7 +1587,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Display a `Snackbar`. if (firstPartyCookiesEnabled) { // First-party cookies are enabled. Snackbar.make(findViewById(R.id.webviewpager), R.string.first_party_cookies_enabled, Snackbar.LENGTH_SHORT).show(); - } else if (javaScriptEnabled) { // JavaScript is still enabled. + } else if (currentWebView.getSettings().getJavaScriptEnabled()) { // JavaScript is still enabled. Snackbar.make(findViewById(R.id.webviewpager), R.string.first_party_cookies_disabled, Snackbar.LENGTH_SHORT).show(); } else { // Privacy mode. Snackbar.make(findViewById(R.id.webviewpager), R.string.privacy_mode, Snackbar.LENGTH_SHORT).show(); @@ -1653,16 +1600,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.toggle_third_party_cookies: if (Build.VERSION.SDK_INT >= 21) { // Switch the status of thirdPartyCookiesEnabled. - thirdPartyCookiesEnabled = !thirdPartyCookiesEnabled; + cookieManager.setAcceptThirdPartyCookies(currentWebView, !cookieManager.acceptThirdPartyCookies(currentWebView)); // Update the menu checkbox. - menuItem.setChecked(thirdPartyCookiesEnabled); - - // Apply the new cookie status. - cookieManager.setAcceptThirdPartyCookies(currentWebView, thirdPartyCookiesEnabled); + menuItem.setChecked(cookieManager.acceptThirdPartyCookies(currentWebView)); - // Display a `Snackbar`. - if (thirdPartyCookiesEnabled) { + // Display a snackbar. + if (cookieManager.acceptThirdPartyCookies(currentWebView)) { Snackbar.make(findViewById(R.id.webviewpager), R.string.third_party_cookies_enabled, Snackbar.LENGTH_SHORT).show(); } else { Snackbar.make(findViewById(R.id.webviewpager), R.string.third_party_cookies_disabled, Snackbar.LENGTH_SHORT).show(); @@ -1674,20 +1618,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return true; case R.id.toggle_dom_storage: - // Switch the status of domStorageEnabled. - domStorageEnabled = !domStorageEnabled; + // Toggle the status of domStorageEnabled. + currentWebView.getSettings().setDomStorageEnabled(!currentWebView.getSettings().getDomStorageEnabled()); // Update the menu checkbox. - menuItem.setChecked(domStorageEnabled); + menuItem.setChecked(currentWebView.getSettings().getDomStorageEnabled()); - // Apply the new DOM Storage status. - currentWebView.getSettings().setDomStorageEnabled(domStorageEnabled); - - // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. + // Update the privacy icon. `true` refreshes the app bar icons. updatePrivacyIcons(true); - // Display a `Snackbar`. - if (domStorageEnabled) { + // Display a snackbar. + if (currentWebView.getSettings().getDomStorageEnabled()) { Snackbar.make(findViewById(R.id.webviewpager), R.string.dom_storage_enabled, Snackbar.LENGTH_SHORT).show(); } else { Snackbar.make(findViewById(R.id.webviewpager), R.string.dom_storage_disabled, Snackbar.LENGTH_SHORT).show(); @@ -1835,10 +1776,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.easylist: // Toggle the EasyList status. - easyListEnabled = !easyListEnabled; + currentWebView.enableBlocklist(NestedScrollWebView.EASY_LIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)); // Update the menu checkbox. - menuItem.setChecked(easyListEnabled); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)); // Reload the current WebView. currentWebView.reload(); @@ -1846,10 +1787,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.easyprivacy: // Toggle the EasyPrivacy status. - easyPrivacyEnabled = !easyPrivacyEnabled; + currentWebView.enableBlocklist(NestedScrollWebView.EASY_PRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)); // Update the menu checkbox. - menuItem.setChecked(easyPrivacyEnabled); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)); // Reload the current WebView. currentWebView.reload(); @@ -1857,14 +1798,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.fanboys_annoyance_list: // Toggle Fanboy's Annoyance List status. - fanboysAnnoyanceListEnabled = !fanboysAnnoyanceListEnabled; + currentWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)); // Update the menu checkbox. - menuItem.setChecked(fanboysAnnoyanceListEnabled); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)); // Update the staus of Fanboy's Social Blocking List. - MenuItem fanboysSocialBlockingListMenuItem = mainMenu.findItem(R.id.fanboys_social_blocking_list); - fanboysSocialBlockingListMenuItem.setEnabled(!fanboysAnnoyanceListEnabled); + MenuItem fanboysSocialBlockingListMenuItem = optionsMenu.findItem(R.id.fanboys_social_blocking_list); + fanboysSocialBlockingListMenuItem.setEnabled(!currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)); // Reload the current WebView. currentWebView.reload(); @@ -1872,10 +1813,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.fanboys_social_blocking_list: // Toggle Fanboy's Social Blocking List status. - fanboysSocialBlockingListEnabled = !fanboysSocialBlockingListEnabled; + currentWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST)); // Update the menu checkbox. - menuItem.setChecked(fanboysSocialBlockingListEnabled); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST)); // Reload the current WebView. currentWebView.reload(); @@ -1883,10 +1824,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.ultraprivacy: // Toggle the UltraPrivacy status. - ultraPrivacyEnabled = !ultraPrivacyEnabled; + currentWebView.enableBlocklist(NestedScrollWebView.ULTRA_PRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)); // Update the menu checkbox. - menuItem.setChecked(ultraPrivacyEnabled); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)); // Reload the current WebView. currentWebView.reload(); @@ -1894,10 +1835,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.block_all_third_party_requests: //Toggle the third-party requests blocker status. - blockAllThirdPartyRequests = !blockAllThirdPartyRequests; + currentWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, !currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)); // Update the menu checkbox. - menuItem.setChecked(blockAllThirdPartyRequests); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)); // Reload the current WebView. currentWebView.reload(); @@ -2001,7 +1942,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.user_agent_custom: // Update the user agent. - currentWebView.getSettings().setUserAgentString(defaultCustomUserAgentString); + currentWebView.getSettings().setUserAgentString(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); // Reload the current WebView. currentWebView.reload(); @@ -2065,23 +2006,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nightMode = !nightMode; // Enable or disable JavaScript according to night mode, the global preference, and any domain settings. - if (nightMode) { // Night mode is enabled. Enable JavaScript. - // Update the global variable. - javaScriptEnabled = true; + if (nightMode) { // Night mode is enabled, which requires JavaScript. + // Enable JavaScript. + currentWebView.getSettings().setJavaScriptEnabled(true); } else if (currentWebView.getDomainSettingsApplied()) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings. - // Get the JavaScript preference that was stored the last time domain settings were loaded. - javaScriptEnabled = domainSettingsJavaScriptEnabled; + // Apply the JavaScript preference that was stored the last time domain settings were loaded. + currentWebView.getSettings().setJavaScriptEnabled(domainSettingsJavaScriptEnabled); } else { // Night mode is disabled and domain settings are not applied. Set JavaScript according to the global preference. - // Get a handle for the shared preference. - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - - // Get the JavaScript preference. - javaScriptEnabled = sharedPreferences.getBoolean("javascript", false); + // Apply the JavaScript preference. + currentWebView.getSettings().setJavaScriptEnabled(sharedPreferences.getBoolean("javascript", false)); } - // Apply the JavaScript setting to the WebView. - currentWebView.getSettings().setJavaScriptEnabled(javaScriptEnabled); - // Update the privacy icons. updatePrivacyIcons(false); @@ -2112,8 +2047,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return true; case R.id.view_source: - // Launch the View Source activity. + // Create an intent to launch the view source activity. Intent viewSourceIntent = new Intent(this, ViewSourceActivity.class); + + // Add the user agent as an extra to the intent. + viewSourceIntent.putExtra("user_agent", currentWebView.getSettings().getUserAgentString()); + + // Make it so. startActivity(viewSourceIntent); return true; @@ -2296,9 +2236,23 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Clear the cache. if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) { - // Clear the cache. - // TODO - currentWebView.clearCache(true); + // Clear the cache from each WebView. + for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); + + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Only clear the cache if the WebView exists. + if (fragmentView != null) { + // Get the nested scroll WebView from the tab fragment. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Clear the cache for this WebView. + nestedScrollWebView.clearCache(true); + } + } // Manually delete the cache directories. try { @@ -2317,24 +2271,36 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // Clear SSL certificate preferences. - // TODO - currentWebView.clearSslPreferences(); + // Wipe out each WebView. + for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); + + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Only wipe out the WebView if it exists. + if (fragmentView != null) { + // Get the nested scroll WebView from the tab fragment. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Clear SSL certificate preferences for this WebView. + nestedScrollWebView.clearSslPreferences(); + + // Clear the back/forward history for this WebView. + nestedScrollWebView.clearHistory(); - // Clear the back/forward history. - // TODO - currentWebView.clearHistory(); + // Destroy the internal state of `mainWebView`. + nestedScrollWebView.destroy(); + } + } - // Clear `formattedUrlString`. + // Clear the formatted URL string. formattedUrlString = null; - // Clear `customHeaders`. + // Clear the custom headers. customHeaders.clear(); - // Destroy the internal state of `mainWebView`. - // TODO - currentWebView.destroy(); - // Manually delete the `app_webview` folder, which contains the cookies, DOM storage, form data, and `Service Worker` cache. // See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`. if (clearEverything) { @@ -2406,6 +2372,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Create an intent to launch the Requests activity. Intent requestsIntent = new Intent(this, RequestsActivity.class); + // Add the block third-party requests status to the intent. + requestsIntent.putExtra("block_all_third_party_requests", currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)); + // Make it so. startActivity(requestsIntent); break; @@ -2423,7 +2392,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.domains: // Set the flag to reapply the domain settings on restart when returning from Domain Settings. reapplyDomainSettingsOnRestart = true; - currentDomainName = ""; + currentWebView.resetCurrentDomainName(); // TODO. Do this for all tabs. + + // TODO. Move these to `putExtra`. The certificate can be stored as strings. + // Store the current SSL certificate and IP addresses in the domains activity. + DomainsActivity.currentSslCertificate = currentWebView.getCertificate(); + DomainsActivity.currentIpAddresses = currentWebView.getCurrentIpAddresses(); // Launch the domains activity. Intent domainsIntent = new Intent(this, DomainsActivity.class); @@ -2436,7 +2410,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the flag to reapply the domain settings on restart when returning from Settings. reapplyDomainSettingsOnRestart = true; - currentDomainName = ""; + currentWebView.resetCurrentDomainName(); // TODO. Do this for all tabs. // Launch the settings activity. Intent settingsIntent = new Intent(this, SettingsActivity.class); @@ -3206,23 +3180,23 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onSslErrorCancel() { + public void onSslErrorCancel() { // TODO. How to handle this with multiple tabs? There could be multiple errors at once. sslErrorHandler.cancel(); } @Override - public void onSslErrorProceed() { + public void onSslErrorProceed() { // TODO. How to handle this with multiple tabs? There could be multiple errors at once. sslErrorHandler.proceed(); } @Override - public void onPinnedMismatchBack() { + public void onPinnedMismatchBack() { // TODO. Move this logic to the dialog. if (currentWebView.canGoBack()) { // There is a back page in the history. // Reset the formatted URL string so the page will load correctly if blocking of third-party requests is enabled. - formattedUrlString = ""; + formattedUrlString = ""; // TODO. // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded. - navigatingHistory = true; + navigatingHistory = true; // TODO. // Go back. currentWebView.goBack(); @@ -3233,9 +3207,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onPinnedMismatchProceed() { + public void onPinnedMismatchProceed() { // TODO. Move this logic to the dialog. // Do not check the pinned information for this domain again until the domain changes. - ignorePinnedDomainInformation = true; + currentWebView.setIgnorePinnedDomainInformation(true); } @Override @@ -3378,10 +3352,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = url; // Apply the domain settings. - applyDomainSettings(url, true, false); - - // If loading a website, set `urlIsLoading` to prevent changes in the user agent on websites with redirects from reloading the current website. - urlIsLoading = !url.equals(""); + applyDomainSettings(currentWebView, url, true, false); // Load the URL. currentWebView.loadUrl(url, customHeaders); @@ -3447,7 +3418,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook customHeaders.remove("DNT"); } - // TODO this also needs to be set when creating a new tab. // Set the app bar scrolling for each WebView. for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { // Get the WebView tab fragment. @@ -3501,7 +3471,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Show the banner ad in the free flavor. if (BuildConfig.FLAVOR.contentEquals("free")) { // Initialize the ads. If this isn't the first run, `loadAd()` will be automatically called instead. - AdHelper.initializeAds(findViewById(R.id.adview), getApplicationContext(), fragmentManager, getString(R.string.google_app_id), getString(R.string.ad_unit_id)); + AdHelper.initializeAds(findViewById(R.id.adview), getApplicationContext(), getSupportFragmentManager(), getString(R.string.google_app_id), getString(R.string.ad_unit_id)); } // Remove the `SYSTEM_UI` flags from the root frame layout. @@ -3514,59 +3484,47 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `reloadWebsite` is used if returning from the Domains activity. Otherwise JavaScript might not function correctly if it is newly enabled. - // The deprecated `.getDrawable()` must be used until the minimum API >= 21. - @SuppressWarnings("deprecation") - private boolean applyDomainSettings(String url, boolean resetFavoriteIcon, boolean reloadWebsite) { - // Get a handle for the URL edit text. - EditText urlEditText = findViewById(R.id.url_edittext); - - // Get the current user agent. - String initialUserAgent = currentWebView.getSettings().getUserAgentString(); + @SuppressLint("SetJavaScriptEnabled") + private boolean applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetFavoriteIcon, boolean reloadWebsite) { + // Get a handle for the URL relative layout. + RelativeLayout urlRelativeLayout = findViewById(R.id.url_relativelayout); - // Initialize a variable to track if the user agent changes. - boolean userAgentChanged = false; + // Store a copy of the current user agent to track changes for the return boolean. + String initialUserAgent = nestedScrollWebView.getSettings().getUserAgentString(); // Parse the URL into a URI. Uri uri = Uri.parse(url); // Extract the domain from `uri`. - String hostName = uri.getHost(); - - // Initialize `loadingNewDomainName`. - boolean loadingNewDomainName; - - // If either `hostName` or `currentDomainName` are `null`, run the options for loading a new domain name. - // The lint suggestion to simplify the `if` statement is incorrect, because `hostName.equals(currentDomainName)` can produce a `null object reference.` - //noinspection SimplifiableIfStatement - if ((hostName == null) || (currentDomainName == null)) { - loadingNewDomainName = true; - } else { // Determine if `hostName` equals `currentDomainName`. - loadingNewDomainName = !hostName.equals(currentDomainName); - } + String newHostName = uri.getHost(); // Strings don't like to be null. - if (hostName == null) { - hostName = ""; + if (newHostName == null) { + newHostName = ""; } // Only apply the domain settings if a new domain is being loaded. This allows the user to set temporary settings for JavaScript, cookies, DOM storage, etc. - if (loadingNewDomainName) { - // Set the new `hostname` as the `currentDomainName`. - currentDomainName = hostName; + if (!nestedScrollWebView.getCurrentDomainName().equals(newHostName)) { + // Set the new host name as the current domain name. + nestedScrollWebView.setCurrentDomainName(newHostName); // Reset the ignoring of pinned domain information. - ignorePinnedDomainInformation = false; + nestedScrollWebView.setIgnorePinnedDomainInformation(false); + + // Clear any pinned SSL certificate or IP addresses. + nestedScrollWebView.clearPinnedSslCertificate(); + nestedScrollWebView.clearPinnedIpAddresses(); // Reset the favorite icon if specified. if (resetFavoriteIcon) { // Store the favorite icon bitmap. - favoriteIconBitmap = favoriteIconDefaultBitmap; + favoriteIconBitmap = favoriteIconDefaultBitmap; // TODO. // Get a handle for the tab layout. TabLayout tabLayout = findViewById(R.id.tablayout); // Get the current tab. - TabLayout.Tab currentTab = tabLayout.getTabAt(tabLayout.getSelectedTabPosition()); + TabLayout.Tab currentTab = tabLayout.getTabAt(tabLayout.getSelectedTabPosition()); // TODO. We need to get the tab for this WebView, which might not be the current tab. // Remove the warning below that the current tab might be null. assert currentTab != null; @@ -3615,163 +3573,187 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook String domainNameInDatabase = null; // Check the hostname against the domain settings set. - if (domainSettingsSet.contains(hostName)) { // The hostname is contained in the domain settings set. + if (domainSettingsSet.contains(newHostName)) { // The hostname is contained in the domain settings set. // Record the domain name in the database. - domainNameInDatabase = hostName; + domainNameInDatabase = newHostName; // Set the domain settings applied tracker to true. - currentWebView.setDomainSettingsApplied(true); + nestedScrollWebView.setDomainSettingsApplied(true); } else { // The hostname is not contained in the domain settings set. // Set the domain settings applied tracker to false. - currentWebView.setDomainSettingsApplied(false); + nestedScrollWebView.setDomainSettingsApplied(false); } // Check all the subdomains of the host name against wildcard domains in the domain cursor. - while (!currentWebView.getDomainSettingsApplied() && hostName.contains(".")) { // Stop checking if domain settings are already applied or there are no more `.` in the host name. - if (domainSettingsSet.contains("*." + hostName)) { // Check the host name prepended by `*.`. + while (!nestedScrollWebView.getDomainSettingsApplied() && newHostName.contains(".")) { // Stop checking if domain settings are already applied or there are no more `.` in the host name. + if (domainSettingsSet.contains("*." + newHostName)) { // Check the host name prepended by `*.`. // Set the domain settings applied tracker to true. - currentWebView.setDomainSettingsApplied(true); + nestedScrollWebView.setDomainSettingsApplied(true); // Store the applied domain names as it appears in the database. - domainNameInDatabase = "*." + hostName; + domainNameInDatabase = "*." + newHostName; } // Strip out the lowest subdomain of of the host name. - hostName = hostName.substring(hostName.indexOf(".") + 1); + newHostName = newHostName.substring(newHostName.indexOf(".") + 1); } - // Get a handle for the shared preference. + // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); // Store the general preference information. String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value)); String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value)); - defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value)); boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true); - nightMode = sharedPreferences.getBoolean("night_mode", false); + nightMode = sharedPreferences.getBoolean("night_mode", false); // TODO. boolean displayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true); - if (currentWebView.getDomainSettingsApplied()) { // The url has custom domain settings. + if (nestedScrollWebView.getDomainSettingsApplied()) { // The url has custom domain settings. // Get a cursor for the current host and move it to the first position. - Cursor currentHostDomainSettingsCursor = domainsDatabaseHelper.getCursorForDomainName(domainNameInDatabase); - currentHostDomainSettingsCursor.moveToFirst(); + Cursor currentDomainSettingsCursor = domainsDatabaseHelper.getCursorForDomainName(domainNameInDatabase); + currentDomainSettingsCursor.moveToFirst(); // Get the settings from the cursor. - currentWebView.setDomainSettingsDatabaseId(currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); - javaScriptEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); - firstPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1); - thirdPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1); - domStorageEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1); + nestedScrollWebView.setDomainSettingsDatabaseId(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); + boolean domainJavaScriptEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); + firstPartyCookiesEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1); // TODO. + boolean domainThirdPartyCookiesEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1); + boolean domainDomStorageEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1); // Form data can be removed once the minimum API >= 26. - saveFormDataEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1); - easyListEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST)) == 1); - easyPrivacyEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY)) == 1); - fanboysAnnoyanceListEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1); - fanboysSocialBlockingListEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)) == 1); - ultraPrivacyEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY)) == 1); - blockAllThirdPartyRequests = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1); - String userAgentName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT)); - int fontSize = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE)); - int swipeToRefreshInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH)); - int nightModeInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE)); - int displayWebpageImagesInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES)); - pinnedSslCertificate = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE)) == 1); - pinnedSslIssuedToCName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME)); - pinnedSslIssuedToOName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION)); - pinnedSslIssuedToUName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT)); - pinnedSslIssuedByCName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME)); - pinnedSslIssuedByOName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION)); - pinnedSslIssuedByUName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT)); - pinnedIpAddresses = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES)) == 1); - pinnedHostIpAddresses = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES)); + saveFormDataEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1); // TODO. + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_LIST, + currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST)) == 1); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_PRIVACY, + currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY)) == 1); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST, + currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST, + currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)) == 1); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRA_PRIVACY, + currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY)) == 1); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, + currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1); + String userAgentName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT)); + int fontSize = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE)); + int swipeToRefreshInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH)); + int nightModeInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE)); + int displayWebpageImagesInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES)); + boolean pinnedSslCertificate = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE)) == 1); + String pinnedSslIssuedToCName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME)); + String pinnedSslIssuedToOName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION)); + String pinnedSslIssuedToUName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT)); + String pinnedSslIssuedByCName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME)); + String pinnedSslIssuedByOName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION)); + String pinnedSslIssuedByUName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT)); + boolean pinnedIpAddresses = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES)) == 1); + String pinnedHostIpAddresses = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES)); + + // Create the pinned SSL date variables. + Date pinnedSslStartDate; + Date pinnedSslEndDate; + + // Set the pinned SSL certificate start date to `null` if the saved date `long` is 0 because creating a new Date results in an error if the input is 0. + if (currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) == 0) { + pinnedSslStartDate = null; + } else { + pinnedSslStartDate = new Date(currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE))); + } + + // Set the pinned SSL certificate end date to `null` if the saved date `long` is 0 because creating a new Date results in an error if the input is 0. + if (currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) == 0) { + pinnedSslEndDate = null; + } else { + pinnedSslEndDate = new Date(currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE))); + } + + // If there is a pinned SSL certificate, store it in the WebView. + if (pinnedSslCertificate) { + nestedScrollWebView.setPinnedSslCertificate(pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName, + pinnedSslStartDate, pinnedSslEndDate); + } + + // If there is a pinned IP address, store it in the WebView. + if (pinnedIpAddresses) { + nestedScrollWebView.setPinnedIpAddresses(pinnedHostIpAddresses); + } // Set `nightMode` according to `nightModeInt`. If `nightModeInt` is `DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT` the current setting from `sharedPreferences` will be used. switch (nightModeInt) { case DomainsDatabaseHelper.NIGHT_MODE_ENABLED: - nightMode = true; + nightMode = true; // TODO. break; case DomainsDatabaseHelper.NIGHT_MODE_DISABLED: - nightMode = false; + nightMode = false; // TODO. break; } + // TODO. // Store the domain JavaScript status. This is used by the options menu night mode toggle. - domainSettingsJavaScriptEnabled = javaScriptEnabled; + domainSettingsJavaScriptEnabled = domainJavaScriptEnabled; // Enable JavaScript if night mode is enabled. if (nightMode) { - javaScriptEnabled = true; - } - - // Set the pinned SSL certificate start date to `null` if the saved date `long` is 0. - if (currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) == 0) { - pinnedSslStartDate = null; - } else { - pinnedSslStartDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE))); - } - - // Set the pinned SSL certificate end date to `null` if the saved date `long` is 0. - if (currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) == 0) { - pinnedSslEndDate = null; + // Enable JavaScript. + nestedScrollWebView.getSettings().setJavaScriptEnabled(true); } else { - pinnedSslEndDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE))); + // Set JavaScript according to the domain settings. + nestedScrollWebView.getSettings().setJavaScriptEnabled(domainJavaScriptEnabled); } // Close `currentHostDomainSettingsCursor`. - currentHostDomainSettingsCursor.close(); + currentDomainSettingsCursor.close(); // Apply the domain settings. - currentWebView.getSettings().setJavaScriptEnabled(javaScriptEnabled); - cookieManager.setAcceptCookie(firstPartyCookiesEnabled); - currentWebView.getSettings().setDomStorageEnabled(domStorageEnabled); + cookieManager.setAcceptCookie(firstPartyCookiesEnabled); //TODO This could be bad. + nestedScrollWebView.getSettings().setDomStorageEnabled(domainDomStorageEnabled); // TODO. Move up. // Apply the form data setting if the API < 26. if (Build.VERSION.SDK_INT < 26) { - currentWebView.getSettings().setSaveFormData(saveFormDataEnabled); + nestedScrollWebView.getSettings().setSaveFormData(saveFormDataEnabled); } // Apply the font size. if (fontSize == 0) { // Apply the default font size. - currentWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); + nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); } else { // Apply the specified font size. - currentWebView.getSettings().setTextZoom(fontSize); + nestedScrollWebView.getSettings().setTextZoom(fontSize); } // Set third-party cookies status if API >= 21. if (Build.VERSION.SDK_INT >= 21) { - cookieManager.setAcceptThirdPartyCookies(currentWebView, thirdPartyCookiesEnabled); + cookieManager.setAcceptThirdPartyCookies(nestedScrollWebView, domainThirdPartyCookiesEnabled); } // Only set the user agent if the webpage is not currently loading. Otherwise, changing the user agent on redirects can cause the original website to reload. // - if (!urlIsLoading) { + if (nestedScrollWebView.getProgress() == 100) { // A URL is not loading. // Set the user agent. if (userAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent. // Get the array position of the default user agent name. - int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName); + int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName); // TODO Could this be local. // Set the user agent according to the system default. switch (defaultUserAgentArrayPosition) { case UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list. // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. - currentWebView.getSettings().setUserAgentString(defaultUserAgentName); + nestedScrollWebView.getSettings().setUserAgentString(defaultUserAgentName); break; case SETTINGS_WEBVIEW_DEFAULT_USER_AGENT: // Set the user agent to `""`, which uses the default value. - currentWebView.getSettings().setUserAgentString(""); + nestedScrollWebView.getSettings().setUserAgentString(""); break; case SETTINGS_CUSTOM_USER_AGENT: - // Set the custom user agent. - currentWebView.getSettings().setUserAgentString(defaultCustomUserAgentString); + // Set the default custom user agent. + nestedScrollWebView.getSettings().setUserAgentString(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); break; default: // Get the user agent string from the user agent data array - currentWebView.getSettings().setUserAgentString(userAgentDataArray[defaultUserAgentArrayPosition]); + nestedScrollWebView.getSettings().setUserAgentString(userAgentDataArray[defaultUserAgentArrayPosition]); } } else { // Set the user agent according to the stored name. // Get the array position of the user agent name. @@ -3779,29 +3761,23 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook switch (userAgentArrayPosition) { case UNRECOGNIZED_USER_AGENT: // The user agent name contains a custom user agent. - currentWebView.getSettings().setUserAgentString(userAgentName); + nestedScrollWebView.getSettings().setUserAgentString(userAgentName); break; case SETTINGS_WEBVIEW_DEFAULT_USER_AGENT: // Set the user agent to `""`, which uses the default value. - currentWebView.getSettings().setUserAgentString(""); + nestedScrollWebView.getSettings().setUserAgentString(""); break; default: // Get the user agent string from the user agent data array. - currentWebView.getSettings().setUserAgentString(userAgentDataArray[userAgentArrayPosition]); + nestedScrollWebView.getSettings().setUserAgentString(userAgentDataArray[userAgentArrayPosition]); } } - - // Store the applied user agent string, which is used in the View Source activity. - appliedUserAgentString = currentWebView.getSettings().getUserAgentString(); - - // Update the user agent change tracker. - userAgentChanged = !appliedUserAgentString.equals(initialUserAgent); } // Set swipe to refresh. - switch (swipeToRefreshInt) { + switch (swipeToRefreshInt) { // TODO. This needs to be set and updated by tab. case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT: // Set swipe to refresh according to the default. swipeRefreshLayout.setEnabled(defaultSwipeToRefresh); @@ -3820,48 +3796,50 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the loading of webpage images. switch (displayWebpageImagesInt) { case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT: - currentWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImages); + nestedScrollWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImages); break; case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED: - currentWebView.getSettings().setLoadsImagesAutomatically(true); + nestedScrollWebView.getSettings().setLoadsImagesAutomatically(true); break; case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED: - currentWebView.getSettings().setLoadsImagesAutomatically(false); + nestedScrollWebView.getSettings().setLoadsImagesAutomatically(false); break; } - // Set a green background on URL edit text to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + // 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) { - urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); } else { - urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); } } else { // The new URL does not have custom domain settings. Load the defaults. - // Store the values from `sharedPreferences` in variables. - javaScriptEnabled = sharedPreferences.getBoolean("javascript", false); - firstPartyCookiesEnabled = sharedPreferences.getBoolean("first_party_cookies", false); - thirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false); - domStorageEnabled = sharedPreferences.getBoolean("dom_storage", false); - saveFormDataEnabled = sharedPreferences.getBoolean("save_form_data", false); // Form data can be removed once the minimum API >= 26. - easyListEnabled = sharedPreferences.getBoolean("easylist", true); - easyPrivacyEnabled = sharedPreferences.getBoolean("easyprivacy", true); - fanboysAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboys_annoyance_list", true); - fanboysSocialBlockingListEnabled = sharedPreferences.getBoolean("fanboys_social_blocking_list", true); - ultraPrivacyEnabled = sharedPreferences.getBoolean("ultraprivacy", true); - blockAllThirdPartyRequests = sharedPreferences.getBoolean("block_all_third_party_requests", false); - - // Set `javaScriptEnabled` to be `true` if `night_mode` is `true`. + // Store the values from the shared preferences. + boolean defaultJavaScriptEnabled = sharedPreferences.getBoolean("javascript", false); + firstPartyCookiesEnabled = sharedPreferences.getBoolean("first_party_cookies", false); // TODO. + boolean defaultThirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false); + nestedScrollWebView.getSettings().setDomStorageEnabled(sharedPreferences.getBoolean("dom_storage", false)); + saveFormDataEnabled = sharedPreferences.getBoolean("save_form_data", false); // Form data can be removed once the minimum API >= 26. // TODO. + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_LIST, sharedPreferences.getBoolean("easylist", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_PRIVACY, sharedPreferences.getBoolean("easyprivacy", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST, sharedPreferences.getBoolean("fanboys_annoyance_list", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST, sharedPreferences.getBoolean("fanboys_social_blocking_list", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRA_PRIVACY, sharedPreferences.getBoolean("ultraprivacy", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, sharedPreferences.getBoolean("block_all_third_party_requests", false)); + + // Enable JavaScript if night mode is enabled. if (nightMode) { - javaScriptEnabled = true; + // Enable JavaScript. + nestedScrollWebView.getSettings().setJavaScriptEnabled(true); + } else { + // Set JavaScript according to the domain settings. + nestedScrollWebView.getSettings().setJavaScriptEnabled(defaultJavaScriptEnabled); } // Apply the default settings. - currentWebView.getSettings().setJavaScriptEnabled(javaScriptEnabled); - cookieManager.setAcceptCookie(firstPartyCookiesEnabled); - currentWebView.getSettings().setDomStorageEnabled(domStorageEnabled); - currentWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); + cookieManager.setAcceptCookie(firstPartyCookiesEnabled); // TODO. + nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); swipeRefreshLayout.setEnabled(defaultSwipeToRefresh); // Apply the form data setting if the API < 26. @@ -3870,27 +3848,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Reset the pinned variables. - currentWebView.setDomainSettingsDatabaseId(-1); - pinnedSslCertificate = false; - pinnedSslIssuedToCName = ""; - pinnedSslIssuedToOName = ""; - pinnedSslIssuedToUName = ""; - pinnedSslIssuedByCName = ""; - pinnedSslIssuedByOName = ""; - pinnedSslIssuedByUName = ""; - pinnedSslStartDate = null; - pinnedSslEndDate = null; - pinnedIpAddresses = false; - pinnedHostIpAddresses = ""; + nestedScrollWebView.setDomainSettingsDatabaseId(-1); // Set third-party cookies status if API >= 21. if (Build.VERSION.SDK_INT >= 21) { - cookieManager.setAcceptThirdPartyCookies(currentWebView, thirdPartyCookiesEnabled); + cookieManager.setAcceptThirdPartyCookies(nestedScrollWebView, defaultThirdPartyCookiesEnabled); } // Only set the user agent if the webpage is not currently loading. Otherwise, changing the user agent on redirects can cause the original website to reload. // - if (!urlIsLoading) { + if (nestedScrollWebView.getProgress() == 100) { // A URL is not loading. // Get the array position of the user agent name. int userAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName); @@ -3898,54 +3865,46 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook switch (userAgentArrayPosition) { case UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list. // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. - currentWebView.getSettings().setUserAgentString(defaultUserAgentName); + nestedScrollWebView.getSettings().setUserAgentString(defaultUserAgentName); break; case SETTINGS_WEBVIEW_DEFAULT_USER_AGENT: // Set the user agent to `""`, which uses the default value. - currentWebView.getSettings().setUserAgentString(""); + nestedScrollWebView.getSettings().setUserAgentString(""); break; case SETTINGS_CUSTOM_USER_AGENT: - // Set the custom user agent. - currentWebView.getSettings().setUserAgentString(defaultCustomUserAgentString); + // Set the default custom user agent. + nestedScrollWebView.getSettings().setUserAgentString(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); break; default: // Get the user agent string from the user agent data array - currentWebView.getSettings().setUserAgentString(userAgentDataArray[userAgentArrayPosition]); + nestedScrollWebView.getSettings().setUserAgentString(userAgentDataArray[userAgentArrayPosition]); } - - // Store the applied user agent string, which is used in the View Source activity. - appliedUserAgentString = currentWebView.getSettings().getUserAgentString(); - - // Update the user agent change tracker. - userAgentChanged = !appliedUserAgentString.equals(initialUserAgent); } // Set the loading of webpage images. - currentWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImages); + nestedScrollWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImages); - // Set a transparent background on URL edit text. The deprecated `.getDrawable()` must be used until the minimum API >= 21. - urlEditText.setBackgroundDrawable(getResources().getDrawable(R.color.transparent)); + // Set a transparent background on URL edit text. The deprecated `getResources().getDrawable()` must be used until the minimum API >= 21. + urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent)); } // Close the domains database helper. domainsDatabaseHelper.close(); - // Update the privacy icons, but only if `mainMenu` has already been populated. - if (mainMenu != null) { - updatePrivacyIcons(true); - } + // Update the privacy icons. + updatePrivacyIcons(true); } // Reload the website if returning from the Domains activity. if (reloadWebsite) { - currentWebView.reload(); + nestedScrollWebView.reload(); } // Return the user agent changed status. - return userAgentChanged; + return !nestedScrollWebView.getSettings().getUserAgentString().equals(initialUserAgent); } private void applyProxyThroughOrbot(boolean reloadWebsite) { @@ -4060,59 +4019,62 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } private void updatePrivacyIcons(boolean runInvalidateOptionsMenu) { - // Get handles for the menu items. - MenuItem privacyMenuItem = mainMenu.findItem(R.id.toggle_javascript); - MenuItem firstPartyCookiesMenuItem = mainMenu.findItem(R.id.toggle_first_party_cookies); - MenuItem domStorageMenuItem = mainMenu.findItem(R.id.toggle_dom_storage); - MenuItem refreshMenuItem = mainMenu.findItem(R.id.refresh); - - // Update the privacy icon. - if (javaScriptEnabled) { // JavaScript is enabled. - privacyMenuItem.setIcon(R.drawable.javascript_enabled); - } else if (firstPartyCookiesEnabled) { // JavaScript is disabled but cookies are enabled. - privacyMenuItem.setIcon(R.drawable.warning); - } else { // All the dangerous features are disabled. - privacyMenuItem.setIcon(R.drawable.privacy_mode); - } + // Only update the privacy icons if the options menu has already been populated. + if (optionsMenu != null) { + // Get handles for the menu items. + MenuItem privacyMenuItem = optionsMenu.findItem(R.id.toggle_javascript); + MenuItem firstPartyCookiesMenuItem = optionsMenu.findItem(R.id.toggle_first_party_cookies); + MenuItem domStorageMenuItem = optionsMenu.findItem(R.id.toggle_dom_storage); + MenuItem refreshMenuItem = optionsMenu.findItem(R.id.refresh); + + // Update the privacy icon. + if (currentWebView.getSettings().getJavaScriptEnabled()) { // JavaScript is enabled. + privacyMenuItem.setIcon(R.drawable.javascript_enabled); + } else if (firstPartyCookiesEnabled) { // JavaScript is disabled but cookies are enabled. + privacyMenuItem.setIcon(R.drawable.warning); + } else { // All the dangerous features are disabled. + privacyMenuItem.setIcon(R.drawable.privacy_mode); + } - // Update the first-party cookies icon. - if (firstPartyCookiesEnabled) { // First-party cookies are enabled. - firstPartyCookiesMenuItem.setIcon(R.drawable.cookies_enabled); - } else { // First-party cookies are disabled. - if (darkTheme) { - firstPartyCookiesMenuItem.setIcon(R.drawable.cookies_disabled_dark); - } else { - firstPartyCookiesMenuItem.setIcon(R.drawable.cookies_disabled_light); + // Update the first-party cookies icon. + if (firstPartyCookiesEnabled) { // First-party cookies are enabled. + firstPartyCookiesMenuItem.setIcon(R.drawable.cookies_enabled); + } else { // First-party cookies are disabled. + if (darkTheme) { + firstPartyCookiesMenuItem.setIcon(R.drawable.cookies_disabled_dark); + } else { + firstPartyCookiesMenuItem.setIcon(R.drawable.cookies_disabled_light); + } } - } - // Update the DOM storage icon. - if (javaScriptEnabled && domStorageEnabled) { // Both JavaScript and DOM storage are enabled. - domStorageMenuItem.setIcon(R.drawable.dom_storage_enabled); - } else if (javaScriptEnabled) { // JavaScript is enabled but DOM storage is disabled. - if (darkTheme) { - domStorageMenuItem.setIcon(R.drawable.dom_storage_disabled_dark); - } else { - domStorageMenuItem.setIcon(R.drawable.dom_storage_disabled_light); + // Update the DOM storage icon. + if (currentWebView.getSettings().getJavaScriptEnabled() && currentWebView.getSettings().getDomStorageEnabled()) { // Both JavaScript and DOM storage are enabled. + domStorageMenuItem.setIcon(R.drawable.dom_storage_enabled); + } else if (currentWebView.getSettings().getJavaScriptEnabled()) { // JavaScript is enabled but DOM storage is disabled. + if (darkTheme) { + domStorageMenuItem.setIcon(R.drawable.dom_storage_disabled_dark); + } else { + domStorageMenuItem.setIcon(R.drawable.dom_storage_disabled_light); + } + } else { // JavaScript is disabled, so DOM storage is ghosted. + if (darkTheme) { + domStorageMenuItem.setIcon(R.drawable.dom_storage_ghosted_dark); + } else { + domStorageMenuItem.setIcon(R.drawable.dom_storage_ghosted_light); + } } - } else { // JavaScript is disabled, so DOM storage is ghosted. + + // Update the refresh icon. if (darkTheme) { - domStorageMenuItem.setIcon(R.drawable.dom_storage_ghosted_dark); + refreshMenuItem.setIcon(R.drawable.refresh_enabled_dark); } else { - domStorageMenuItem.setIcon(R.drawable.dom_storage_ghosted_light); + refreshMenuItem.setIcon(R.drawable.refresh_enabled_light); } - } - - // Update the refresh icon. - if (darkTheme) { - refreshMenuItem.setIcon(R.drawable.refresh_enabled_dark); - } else { - refreshMenuItem.setIcon(R.drawable.refresh_enabled_light); - } - // `invalidateOptionsMenu` calls `onPrepareOptionsMenu()` and redraws the icons in the `AppBar`. - if (runInvalidateOptionsMenu) { - invalidateOptionsMenu(); + // `invalidateOptionsMenu` calls `onPrepareOptionsMenu()` and redraws the icons in the `AppBar`. + if (runInvalidateOptionsMenu) { + invalidateOptionsMenu(); + } } } @@ -4273,73 +4235,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook startActivity(openWithBrowserIntent); } - public static void checkPinnedMismatch(int domainSettingsDatabaseId) { - if ((pinnedSslCertificate || pinnedIpAddresses) && !ignorePinnedDomainInformation) { - // Initialize the current SSL certificate variables. - String currentWebsiteIssuedToCName = ""; - String currentWebsiteIssuedToOName = ""; - String currentWebsiteIssuedToUName = ""; - String currentWebsiteIssuedByCName = ""; - String currentWebsiteIssuedByOName = ""; - String currentWebsiteIssuedByUName = ""; - Date currentWebsiteSslStartDate = null; - Date currentWebsiteSslEndDate = null; - - - // Extract the individual pieces of information from the current website SSL certificate if it is not null. - if (sslCertificate != null) { - currentWebsiteIssuedToCName = sslCertificate.getIssuedTo().getCName(); - currentWebsiteIssuedToOName = sslCertificate.getIssuedTo().getOName(); - currentWebsiteIssuedToUName = sslCertificate.getIssuedTo().getUName(); - currentWebsiteIssuedByCName = sslCertificate.getIssuedBy().getCName(); - currentWebsiteIssuedByOName = sslCertificate.getIssuedBy().getOName(); - currentWebsiteIssuedByUName = sslCertificate.getIssuedBy().getUName(); - currentWebsiteSslStartDate = sslCertificate.getValidNotBeforeDate(); - currentWebsiteSslEndDate = sslCertificate.getValidNotAfterDate(); - } - - // Initialize string variables to store the SSL certificate dates. Strings are needed to compare the values below, which doesn't work with `Dates` if they are `null`. - String currentWebsiteSslStartDateString = ""; - String currentWebsiteSslEndDateString = ""; - String pinnedSslStartDateString = ""; - String pinnedSslEndDateString = ""; - - // Convert the `Dates` to `Strings` if they are not `null`. - if (currentWebsiteSslStartDate != null) { - currentWebsiteSslStartDateString = currentWebsiteSslStartDate.toString(); - } - - if (currentWebsiteSslEndDate != null) { - currentWebsiteSslEndDateString = currentWebsiteSslEndDate.toString(); - } - - if (pinnedSslStartDate != null) { - pinnedSslStartDateString = pinnedSslStartDate.toString(); - } - - if (pinnedSslEndDate != null) { - pinnedSslEndDateString = pinnedSslEndDate.toString(); - } - - // Check to see if the pinned information matches the current information. - if ((pinnedIpAddresses && !currentHostIpAddresses.equals(pinnedHostIpAddresses)) || (pinnedSslCertificate && (!currentWebsiteIssuedToCName.equals(pinnedSslIssuedToCName) || - !currentWebsiteIssuedToOName.equals(pinnedSslIssuedToOName) || !currentWebsiteIssuedToUName.equals(pinnedSslIssuedToUName) || - !currentWebsiteIssuedByCName.equals(pinnedSslIssuedByCName) || !currentWebsiteIssuedByOName.equals(pinnedSslIssuedByOName) || - !currentWebsiteIssuedByUName.equals(pinnedSslIssuedByUName) || !currentWebsiteSslStartDateString.equals(pinnedSslStartDateString) || - !currentWebsiteSslEndDateString.equals(pinnedSslEndDateString)))) { - - // Get a handle for the pinned mismatch alert dialog. - DialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(domainSettingsDatabaseId, pinnedSslCertificate, pinnedIpAddresses); - - // Show the pinned mismatch alert dialog. - pinnedMismatchDialogFragment.show(fragmentManager, "Pinned Mismatch"); - } - } - } - public void addTab(View view) { - // Get a handle for the tab layout. + // Get a handle for the tab layout and the view pager. TabLayout tabLayout = findViewById(R.id.tablayout); + ViewPager webViewPager = findViewById(R.id.webviewpager); // Get the new page number. The page numbers are 0 indexed, so the new page number will match the current count. int newTabNumber = tabLayout.getTabCount(); @@ -4353,20 +4252,15 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Remove the lint warning below that the current tab might be null. assert newTab != null; - // Set a custom view on the current tab. + // Set a custom view on the new tab. newTab.setCustomView(R.layout.custom_tab_view); // Add the new WebView page. - webViewPagerAdapter.addPage(newTabNumber); - - if (newTabNumber > 0) { - // Move to the new tab. - newTab.select(); - } + webViewPagerAdapter.addPage(newTabNumber, webViewPager); } @Override - public void initializeWebView(long pageId, int pageNumber, ProgressBar progressBar, NestedScrollWebView nestedScrollWebView) { + public void initializeWebView(NestedScrollWebView nestedScrollWebView, int pageNumber, ProgressBar progressBar) { // Get handles for the activity views. FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout); DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); @@ -4379,12 +4273,18 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Remove the incorrect lint warnings below that the some of the views might be null. assert actionBar != null; + // Get a handle for the activity + Activity activity = this; + // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); // Get the relevant preferences. boolean downloadWithExternalApp = sharedPreferences.getBoolean("download_with_external_app", false); + // Set the app bar scrolling. + nestedScrollWebView.setNestedScrollingEnabled(sharedPreferences.getBoolean("scroll_app_bar", true)); + // Allow pinch to zoom. nestedScrollWebView.getSettings().setBuiltInZoomControls(true); @@ -4500,22 +4400,22 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook downloadContentLength = contentLength; // Show a dialog if the user has previously denied the permission. - if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first. + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first. // Instantiate the download location permission alert dialog and set the download type to DOWNLOAD_FILE. DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_FILE); // Show the download location permission alert dialog. The permission will be requested when the the dialog is closed. - downloadLocationPermissionDialogFragment.show(fragmentManager, getString(R.string.download_location)); + downloadLocationPermissionDialogFragment.show(getSupportFragmentManager(), getString(R.string.download_location)); } else { // Show the permission request directly. // Request the permission. The download dialog will be launched by `onRequestPermissionResult()`. - ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_FILE_REQUEST_CODE); + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_FILE_REQUEST_CODE); } } else { // The storage permission has already been granted. // Get a handle for the download file alert dialog. DialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength); // Show the download file alert dialog. - downloadFileDialogFragment.show(fragmentManager, getString(R.string.download)); + downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download)); } } }); @@ -4605,7 +4505,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook favoriteIconBitmap = icon; // Get the current page position. - int currentPosition = webViewPagerAdapter.getPositionForId(pageId); + int currentPosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); // Get the current tab. TabLayout.Tab tab = tabLayout.getTabAt(currentPosition); @@ -4631,7 +4531,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override public void onReceivedTitle(WebView view, String title) { // Get the current page position. - int currentPosition = webViewPagerAdapter.getPositionForId(pageId); + int currentPosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); // Get the current tab. TabLayout.Tab tab = tabLayout.getTabAt(currentPosition); @@ -4780,7 +4680,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = ""; // Apply the domain settings for the new URL. `applyDomainSettings` doesn't do anything if the domain has not changed. - boolean userAgentChanged = applyDomainSettings(url, true, false); + boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false); // Check if the user agent has changed. if (userAgentChanged) { @@ -4897,19 +4797,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Get the current WebView page position. - int webViewPagePosition = webViewPagerAdapter.getPositionForId(pageId); + int webViewPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); // Determine if the WebView is currently displayed. boolean webViewDisplayed = (webViewPagePosition == tabLayout.getSelectedTabPosition()); // Block third-party requests if enabled. - if (isThirdPartyRequest && blockAllThirdPartyRequests) { + if (isThirdPartyRequest && nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)) { // Add the result to the resource requests. nestedScrollWebView.addResourceRequest(new String[]{BlockListHelper.REQUEST_THIRD_PARTY, url}); // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.THIRD_PARTY_BLOCKED_REQUESTS); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -4918,7 +4818,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the menu item titles. navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - blockAllThirdPartyRequestsMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_BLOCKED_REQUESTS) + " - " + + blockAllThirdPartyRequestsMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS) + " - " + getString(R.string.block_all_third_party_requests)); }); } @@ -4928,7 +4828,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Check UltraPrivacy if it is enabled. - if (ultraPrivacyEnabled) { + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)) { // Check the URL against UltraPrivacy. String[] ultraPrivacyResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, ultraPrivacy); @@ -4940,7 +4840,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.ULTRA_PRIVACY_BLOCKED_REQUESTS); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.ULTRA_PRIVACY); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -4949,7 +4849,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the menu item titles. navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - ultraPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY_BLOCKED_REQUESTS) + " - " + getString(R.string.ultraprivacy)); + ultraPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY) + " - " + getString(R.string.ultraprivacy)); }); } @@ -4966,7 +4866,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Check EasyList if it is enabled. - if (easyListEnabled) { + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)) { // Check the URL against EasyList. String[] easyListResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyList); @@ -4977,7 +4877,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_LIST_BLOCKED_REQUESTS); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_LIST); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -4986,7 +4886,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the menu item titles. navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - easyListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_LIST_BLOCKED_REQUESTS) + " - " + getString(R.string.easylist)); + easyListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_LIST) + " - " + getString(R.string.easylist)); }); } @@ -4999,7 +4899,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Check EasyPrivacy if it is enabled. - if (easyPrivacyEnabled) { + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)) { // Check the URL against EasyPrivacy. String[] easyPrivacyResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyPrivacy); @@ -5011,7 +4911,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_PRIVACY_BLOCKED_REQUESTS); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_PRIVACY); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -5020,7 +4920,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the menu item titles. navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - easyPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY_BLOCKED_REQUESTS) + " - " + getString(R.string.easyprivacy)); + easyPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY) + " - " + getString(R.string.easyprivacy)); }); } @@ -5033,7 +4933,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Check Fanboy’s Annoyance List if it is enabled. - if (fanboysAnnoyanceListEnabled) { + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)) { // Check the URL against Fanboy's Annoyance List. String[] fanboysAnnoyanceListResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, fanboysAnnoyanceList); @@ -5045,7 +4945,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -5054,7 +4954,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the menu item titles. navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - fanboysAnnoyanceListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS) + " - " + + fanboysAnnoyanceListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST) + " - " + getString(R.string.fanboys_annoyance_list)); }); } @@ -5066,7 +4966,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook whitelistResultStringArray = new String[] {fanboysAnnoyanceListResults[0], fanboysAnnoyanceListResults[1], fanboysAnnoyanceListResults[2], fanboysAnnoyanceListResults[3], fanboysAnnoyanceListResults[4], fanboysAnnoyanceListResults[5]}; } - } else if (fanboysSocialBlockingListEnabled) { // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled. + } else if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST)) { // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled. // Check the URL against Fanboy's Annoyance List. String[] fanboysSocialListResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, fanboysSocialList); @@ -5078,7 +4978,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -5087,7 +4987,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the menu item titles. navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - fanboysSocialBlockingListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS) + " - " + + fanboysSocialBlockingListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST) + " - " + getString(R.string.fanboys_social_blocking_list)); }); } @@ -5120,30 +5020,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Display the HTTP authentication dialog. DialogFragment httpAuthenticationDialogFragment = HttpAuthenticationDialog.displayDialog(host, realm); - httpAuthenticationDialogFragment.show(fragmentManager, getString(R.string.http_authentication)); + httpAuthenticationDialogFragment.show(getSupportFragmentManager(), getString(R.string.http_authentication)); } - // Update the URL in urlTextBox when the page starts to load. @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - // Set `urlIsLoading` to `true`, so that redirects while loading do not trigger changes in the user agent, which forces another reload of the existing page. - // This is also used to determine when to check for pinned mismatches. - urlIsLoading = true; - - // Reset the list of host IP addresses. - currentHostIpAddresses = ""; - // Reset the list of resource requests. nestedScrollWebView.clearResourceRequests(); - // Initialize the counters for requests blocked by each blocklist. - nestedScrollWebView.resetRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.resetRequestsCount(NestedScrollWebView.EASY_LIST_BLOCKED_REQUESTS); - nestedScrollWebView.resetRequestsCount(NestedScrollWebView.EASY_PRIVACY_BLOCKED_REQUESTS); - nestedScrollWebView.resetRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS); - nestedScrollWebView.resetRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS); - nestedScrollWebView.resetRequestsCount(NestedScrollWebView.ULTRA_PRIVACY_BLOCKED_REQUESTS); - nestedScrollWebView.resetRequestsCount(NestedScrollWebView.THIRD_PARTY_BLOCKED_REQUESTS); + // Reset the requests counters. + nestedScrollWebView.resetRequestsCounters(); // If night mode is enabled, hide `mainWebView` until after the night mode CSS is applied. if (nightMode) { @@ -5167,13 +5053,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get a URI for the current URL. Uri currentUri = Uri.parse(formattedUrlString); + // Reset the list of host IP addresses. + nestedScrollWebView.clearCurrentIpAddresses(); + // Get the IP addresses for the host. - new GetHostIpAddresses(activity, currentWebView.getDomainSettingsDatabaseId()).execute(currentUri.getHost()); + new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost()); // Apply any custom domain settings if the URL was loaded by navigating history. if (navigatingHistory) { // Apply the domain settings. - boolean userAgentChanged = applyDomainSettings(url, true, false); + boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false); // Reset `navigatingHistory`. navigatingHistory = false; @@ -5268,7 +5157,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook inputMethodManager.showSoftInput(urlEditText, 0); // Apply the domain settings. This clears any settings from the previous domain. - applyDomainSettings(formattedUrlString, true, false); + applyDomainSettings(nestedScrollWebView, formattedUrlString, true, false); } else { // `WebView` has loaded a webpage. // Set the formatted URL string. Getting the URL from the WebView instead of using the one provided by `onPageFinished` makes websites like YouTube function correctly. formattedUrlString = nestedScrollWebView.getUrl(); @@ -5283,17 +5172,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // Store the SSL certificate so it can be accessed from `ViewSslCertificateDialog` and `PinnedMismatchDialog`. - sslCertificate = nestedScrollWebView.getCertificate(); - // Check the current website information against any pinned domain information if the current IP addresses have been loaded. - if (!gettingIpAddresses) { - checkPinnedMismatch(currentWebView.getDomainSettingsDatabaseId()); + if ((nestedScrollWebView.hasPinnedSslCertificate() || nestedScrollWebView.hasPinnedIpAddresses()) && nestedScrollWebView.hasCurrentIpAddresses() && + !nestedScrollWebView.ignorePinnedDomainInformation()) { + CheckPinnedMismatchHelper.checkPinnedMismatch(getSupportFragmentManager(), nestedScrollWebView); } } - - // Reset `urlIsLoading`, which is used to prevent reloads on redirect if the user agent changes. It is also used to determine when to check for pinned mismatches. - urlIsLoading = false; } // Handle SSL Certificate errors. @@ -5313,21 +5197,30 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook Date currentWebsiteSslEndDate = currentWebsiteSslCertificate.getValidNotAfterDate(); // Proceed to the website if the current SSL website certificate matches the pinned domain certificate. - if (pinnedSslCertificate && - currentWebsiteIssuedToCName.equals(pinnedSslIssuedToCName) && currentWebsiteIssuedToOName.equals(pinnedSslIssuedToOName) && - currentWebsiteIssuedToUName.equals(pinnedSslIssuedToUName) && currentWebsiteIssuedByCName.equals(pinnedSslIssuedByCName) && - currentWebsiteIssuedByOName.equals(pinnedSslIssuedByOName) && currentWebsiteIssuedByUName.equals(pinnedSslIssuedByUName) && - currentWebsiteSslStartDate.equals(pinnedSslStartDate) && currentWebsiteSslEndDate.equals(pinnedSslEndDate)) { - - // An SSL certificate is pinned and matches the current domain certificate. Proceed to the website without displaying an error. - handler.proceed(); + if (nestedScrollWebView.hasPinnedSslCertificate()) { + // Get the pinned SSL certificate. + ArrayList pinnedSslCertificateArrayList = nestedScrollWebView.getPinnedSslCertificate(); + + // Extract the arrays from the array list. + String[] pinnedSslCertificateStringArray = (String[]) pinnedSslCertificateArrayList.get(0); + Date[] pinnedSslCertificateDateArray = (Date[]) pinnedSslCertificateArrayList.get(1); + + // Check if the current SSL certificate matches the pinned certificate. + if (currentWebsiteIssuedToCName.equals(pinnedSslCertificateStringArray[0]) && currentWebsiteIssuedToOName.equals(pinnedSslCertificateStringArray[1]) && + currentWebsiteIssuedToUName.equals(pinnedSslCertificateStringArray[2]) && currentWebsiteIssuedByCName.equals(pinnedSslCertificateStringArray[3]) && + currentWebsiteIssuedByOName.equals(pinnedSslCertificateStringArray[4]) && currentWebsiteIssuedByUName.equals(pinnedSslCertificateStringArray[5]) && + currentWebsiteSslStartDate.equals(pinnedSslCertificateDateArray[0]) && currentWebsiteSslEndDate.equals(pinnedSslCertificateDateArray[1])) { + + // An SSL certificate is pinned and matches the current domain certificate. Proceed to the website without displaying an error. + handler.proceed(); + } } else { // Either there isn't a pinned SSL certificate or it doesn't match the current website certificate. // Store `handler` so it can be accesses from `onSslErrorCancel()` and `onSslErrorProceed()`. - sslErrorHandler = handler; + 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. // Display the SSL error `AlertDialog`. DialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error); - sslCertificateErrorDialogFragment.show(fragmentManager, getString(R.string.ssl_certificate_error)); + sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_error)); } } });