X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FMainWebViewActivity.kt;h=5f103f509a7871795eaf5ff747e1c4e01660a133;hb=f86528a305568aca6738e194a5e5330a85f6f993;hp=2c7560d6c459a90370f0bed7f6f77a2fdefa81ec;hpb=a9d00f526a6fc67f97d479188fae66dd7f0a6dde;p=PrivacyBrowserAndroid.git diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt index 2c7560d6..5f103f50 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt @@ -283,6 +283,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook private lateinit var navigationForwardMenuItem: MenuItem private lateinit var navigationHistoryMenuItem: MenuItem private lateinit var navigationRequestsMenuItem: MenuItem + private lateinit var navigationScrollToBottomMenuItem: MenuItem private lateinit var navigationView: NavigationView private lateinit var optionsAddOrEditDomainMenuItem: MenuItem private lateinit var optionsBlockAllThirdPartyRequestsMenuItem: MenuItem @@ -319,7 +320,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook private lateinit var optionsUserAgentFirefoxOnAndroidMenuItem: MenuItem private lateinit var optionsUserAgentFirefoxOnLinuxMenuItem: MenuItem private lateinit var optionsUserAgentFirefoxOnWindowsMenuItem: MenuItem - private lateinit var optionsUserAgentInternetExplorerOnWindowsMenuItem: MenuItem private lateinit var optionsUserAgentMenuItem: MenuItem private lateinit var optionsUserAgentPrivacyBrowserMenuItem: MenuItem private lateinit var optionsUserAgentSafariOnIosMenuItem: MenuItem @@ -344,7 +344,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook private lateinit var urlEditText: EditText private lateinit var urlRelativeLayout: RelativeLayout private lateinit var userAgentDataArray: Array - private lateinit var userAgentNamesArray: ArrayAdapter + private lateinit var userAgentNamesArray: Array + private lateinit var userAgentDataArrayAdapter: ArrayAdapter + private lateinit var userAgentNamesArrayAdapter: ArrayAdapter // Define the class variables. private var actionBarDrawerToggle: ActionBarDrawerToggle? = null @@ -385,7 +387,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook private var orbotStatusBroadcastReceiver: BroadcastReceiver? = null private var reapplyAppSettingsOnRestart = false private var reapplyDomainSettingsOnRestart = false - private var restartTime = Date(0) private var sanitizeAmpRedirects = false private var sanitizeTrackingQueries = false private var savedProxyMode: String? = null @@ -606,6 +607,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Get handles for the navigation menu items. navigationBackMenuItem = navigationMenu.findItem(R.id.back) navigationForwardMenuItem = navigationMenu.findItem(R.id.forward) + navigationScrollToBottomMenuItem = navigationMenu.findItem(R.id.scroll_to_bottom) navigationHistoryMenuItem = navigationMenu.findItem(R.id.history) navigationRequestsMenuItem = navigationMenu.findItem(R.id.requests) @@ -783,11 +785,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook } } } else { // The app has been restarted. - // If the new intent will open a new tab, set the saved tab position to be the size of the saved state array list. - // The tab position is 0 based, meaning the new tab will be the tab position that is restored. - if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch) - savedTabPosition = savedStateArrayList!!.size - // Replace the intent that started the app with this one. This will load the tab after the others have been restored. setIntent(intent) } @@ -1071,7 +1068,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook optionsUserAgentFirefoxOnWindowsMenuItem = menu.findItem(R.id.user_agent_firefox_on_windows) optionsUserAgentChromeOnWindowsMenuItem = menu.findItem(R.id.user_agent_chrome_on_windows) optionsUserAgentEdgeOnWindowsMenuItem = menu.findItem(R.id.user_agent_edge_on_windows) - optionsUserAgentInternetExplorerOnWindowsMenuItem = menu.findItem(R.id.user_agent_internet_explorer_on_windows) optionsUserAgentSafariOnMacosMenuItem = menu.findItem(R.id.user_agent_safari_on_macos) optionsUserAgentCustomMenuItem = menu.findItem(R.id.user_agent_custom) optionsSwipeToRefreshMenuItem = menu.findItem(R.id.swipe_to_refresh) @@ -1345,15 +1341,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook optionsUserAgentEdgeOnWindowsMenuItem.isChecked = true } - resources.getStringArray(R.array.user_agent_data)[10] -> { // Internet Explorer on Windows. - // Update the user agent menu item title. - optionsUserAgentMenuItem.title = getString(R.string.options_user_agent) + " - " + getString(R.string.user_agent_internet_explorer_on_windows) - - // Select the Internet on Windows radio box. - optionsUserAgentInternetExplorerOnWindowsMenuItem.isChecked = true - } - - resources.getStringArray(R.array.user_agent_data)[11] -> { // Safari on macOS. + resources.getStringArray(R.array.user_agent_data)[10] -> { // Safari on macOS. // Update the user agent menu item title. optionsUserAgentMenuItem.title = getString(R.string.options_user_agent) + " - " + getString(R.string.user_agent_safari_on_macos) @@ -1853,20 +1841,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook true } - R.id.user_agent_internet_explorer_on_windows -> { // User Agent - Internet Explorer on Windows. - // Update the user agent. - currentWebView!!.settings.userAgentString = resources.getStringArray(R.array.user_agent_data)[10] - - // Reload the current WebView. - currentWebView!!.reload() - - // Consume the event. - true - } - R.id.user_agent_safari_on_macos -> { // User Agent - Safari on macOS. // Update the user agent. - currentWebView!!.settings.userAgentString = resources.getStringArray(R.array.user_agent_data)[11] + currentWebView!!.settings.userAgentString = resources.getStringArray(R.array.user_agent_data)[10] // Reload the current WebView. currentWebView!!.reload() @@ -2117,7 +2094,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook } R.id.add_or_edit_domain -> { // Add or edit domain. - // Reapply the domain settings on returning to `MainWebViewActivity`. + // Reapply the domain settings on returning to the main WebView activity. reapplyDomainSettingsOnRestart = true // Check if domain settings are currently applied. @@ -2166,8 +2143,118 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Get the current domain from the URI. Use an empty string if it is null. val currentDomain = currentUri.host?: "" + // Get the current settings status. + val javaScriptInt = calculateSettingsInt(currentWebView!!.settings.javaScriptEnabled, sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) + val cookiesInt = calculateSettingsInt(currentWebView!!.acceptCookies, sharedPreferences.getBoolean(getString(R.string.cookies_key), false)) + val domStorageInt = calculateSettingsInt(currentWebView!!.settings.domStorageEnabled, sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) + val easyListInt = calculateSettingsInt(currentWebView!!.easyListEnabled, sharedPreferences.getBoolean(getString(R.string.easylist_key), true)) + val easyPrivacyInt = calculateSettingsInt(currentWebView!!.easyPrivacyEnabled, sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true)) + val fanboysAnnoyanceListInt = calculateSettingsInt(currentWebView!!.fanboysAnnoyanceListEnabled, sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)) + val fanboysSocialBlockingListInt = calculateSettingsInt(currentWebView!!.fanboysSocialBlockingListEnabled, sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)) + val ultraListInt = calculateSettingsInt(currentWebView!!.ultraListEnabled, sharedPreferences.getBoolean(getString(R.string.ultralist_key), true)) + val ultraPrivacyInt = calculateSettingsInt(currentWebView!!.ultraPrivacyEnabled, sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true)) + val blockAllThirdPartyRequestsInt = calculateSettingsInt(currentWebView!!.blockAllThirdPartyRequests, sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), true)) + val swipeToRefreshInt = calculateSettingsInt(currentWebView!!.swipeToRefresh, sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true)) + val wideViewportInt = calculateSettingsInt(currentWebView!!.settings.useWideViewPort, sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true)) + val displayImagesInt = calculateSettingsInt(currentWebView!!.settings.loadsImagesAutomatically, sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true)) + + // Initialize the form data int. + var formDataInt = SYSTEM_DEFAULT + + // Set the form data int, which can be removed once the minimum API >= 26. + @Suppress("DEPRECATION") + if (Build.VERSION.SDK_INT < 26) { + // Get the form data status. + val formDataEnabled = currentWebView!!.settings.saveFormData + + // Calculate the form data Int. + formDataInt = calculateSettingsInt(formDataEnabled, sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false)) + } + + // Get the current user agent string. + val currentUserAgentString = currentWebView!!.settings.userAgentString + + // Get the user agent string array position. + val userAgentStringArrayPosition = userAgentDataArrayAdapter.getPosition(currentUserAgentString) + + // Set the user agent name. + val userAgentName = if ((userAgentStringArrayPosition >= 0) && (defaultUserAgentName == userAgentNamesArray[userAgentStringArrayPosition])) { // The system default user agent is in use. + getString(R.string.system_default_user_agent) + } else { // An on-the-fly user agent is being used (or the WebView default user agent is applied). + when (userAgentStringArrayPosition) { + UNRECOGNIZED_USER_AGENT -> { // The user agent is unrecognized. + if (currentUserAgentString == webViewDefaultUserAgent) { // The WebView default user agent is being used. + if (defaultUserAgentName == getString(R.string.webview_default)) { // The WebView default user agent is the system default. + // Set the user agent name to be the system default. + getString(R.string.system_default_user_agent) + } else { // The WebView default user agent is set as an on-the-fly setting. + // Set the default user agent name. + getString(R.string.webview_default) + } + } else { // A custom user agent is being used. + if (defaultUserAgentName == getString(R.string.custom_user_agent_non_translatable)) { // The system custom user agent is in use. + // Set the user agent name to be the system default. + getString(R.string.system_default_user_agent) + } else { // An on-the-fly custom user agent is in use. + // Store the user agent as currently applied. + currentUserAgentString + } + } + } + + else -> // Store the standard user agent name. + userAgentNamesArray[userAgentStringArrayPosition] + } + } + + // Get the current text zoom integer. + val textZoomInt = currentWebView!!.settings.textZoom + + // Set the font size integer. + val fontSizeInt = if (textZoomInt == defaultFontSizeString.toInt()) // The current system default is used, which is encoded as a zoom of `0`. + 0 + else // A custom font size is used. + textZoomInt + + // Get the current WebView dark theme status. + val webViewDarkThemeCurrentlyEnabled = if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) // Algorithmic darkening is supported. + WebSettingsCompat.isAlgorithmicDarkeningAllowed(currentWebView!!.settings) + else // Algorithmic darkening is not supported. + false + + // Get the default WebView dark theme setting. + val defaultWebViewDarkThemeEnabled = if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // Algorithmic darkening is supported. + when (defaultWebViewTheme) { + webViewThemeEntryValuesStringArray[1] -> // The dark theme is disabled by default. + false + + webViewThemeEntryValuesStringArray[2] -> // The dark theme is enabled by default. + true + + else -> { // The system default theme is selected. + // Get the current app theme status. + val currentAppThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK + + // Check if the current app theme is dark. + currentAppThemeStatus == Configuration.UI_MODE_NIGHT_YES + } + } + } else { // Algorithmic darkening is not supported. + false + } + + // Set the WebView theme int. + val webViewThemeInt = if (webViewDarkThemeCurrentlyEnabled == defaultWebViewDarkThemeEnabled) // The current WebView theme matches the default. + SYSTEM_DEFAULT + else if (webViewDarkThemeCurrentlyEnabled) // The current WebView theme is dark and that is not the default. + DARK_THEME + else // The current WebView theme is light and that is not the default. + LIGHT_THEME + // Create the domain and store the database ID. - val newDomainDatabaseId = domainsDatabaseHelper!!.addDomain(currentDomain) + val newDomainDatabaseId = domainsDatabaseHelper!!.addDomain(currentDomain, javaScriptInt, cookiesInt, domStorageInt, formDataInt, userAgentName, easyListInt, easyPrivacyInt, + fanboysAnnoyanceListInt, fanboysSocialBlockingListInt, ultraListInt, ultraPrivacyInt, blockAllThirdPartyRequestsInt, fontSizeInt, + swipeToRefreshInt, webViewThemeInt, wideViewportInt, displayImagesInt) // Create an intent to launch the domains activity. val domainsIntent = Intent(this, DomainsActivity::class.java) @@ -2272,6 +2359,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook } } + R.id.scroll_to_bottom -> { // Scroll to Bottom. + // Check if the WebView is scrolled to the top. + if (currentWebView!!.scrollY == 0) { // The WebView is at the top; scroll to the bottom. Using a large Y number is more efficient than trying to calculate the exact WebView length. + currentWebView!!.scrollTo(0, 1_000_000_000) + } else { // The WebView is not at the top; scroll to the top. + currentWebView!!.scrollTo(0, 0) + } + } + R.id.history -> { // History. // Instantiate the URL history dialog. val urlHistoryDialogFragment: DialogFragment = UrlHistoryDialog.loadBackForwardList(currentWebView!!.webViewFragmentId) @@ -2540,6 +2636,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook true } + // Add a Share URL entry. + contextMenu.add(R.string.share_url).setOnMenuItemClickListener { + // Create the share intent. + val shareUrlIntent = Intent(Intent.ACTION_SEND) + + // Add the URL to the intent. + shareUrlIntent.putExtra(Intent.EXTRA_TEXT, linkUrl) + + // Set the MIME type. + shareUrlIntent.type = "text/plain" + + // Set the intent to open in a new task. + shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + + //Make it so. + startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url))) + + // Consume the event. + true + } + // Add an empty cancel entry, which by default closes the context menu. contextMenu.add(R.string.cancel) } @@ -2616,6 +2733,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook true } + // Add a Share URL entry. + contextMenu.add(R.string.share_url).setOnMenuItemClickListener { + // Create the share intent. + val shareUrlIntent = Intent(Intent.ACTION_SEND) + + // Add the URL to the intent. + shareUrlIntent.putExtra(Intent.EXTRA_TEXT, imageUrl) + + // Set the MIME type. + shareUrlIntent.type = "text/plain" + + // Set the intent to open in a new task. + shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + + //Make it so. + startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url))) + + // Consume the event. + true + } + // Add an empty cancel entry, which by default closes the context menu. contextMenu.add(R.string.cancel) } @@ -2706,6 +2844,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook true } + // Add a Share Image entry. + contextMenu.add(R.string.share_image).setOnMenuItemClickListener { + // Create the share intent. + val shareUrlIntent = Intent(Intent.ACTION_SEND) + + // Add the URL to the intent. + shareUrlIntent.putExtra(Intent.EXTRA_TEXT, imageUrl) + + // Set the MIME type. + shareUrlIntent.type = "text/plain" + + // Set the intent to open in a new task. + shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + + //Make it so. + startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url))) + + // Consume the event. + true + } + // Add a copy URL entry. contextMenu.add(R.string.copy_url).setOnMenuItemClickListener { // Save the link URL in a clip data. @@ -2730,6 +2889,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook true } + // Add a Share URL entry. + contextMenu.add(R.string.share_url).setOnMenuItemClickListener { + // Create the share intent. + val shareUrlIntent = Intent(Intent.ACTION_SEND) + + // Add the URL to the intent. + shareUrlIntent.putExtra(Intent.EXTRA_TEXT, linkUrl) + + // Set the MIME type. + shareUrlIntent.type = "text/plain" + + // Set the intent to open in a new task. + shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + + //Make it so. + startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url))) + + // Consume the event. + true + } + // Add an empty cancel entry, which by default closes the context menu. contextMenu.add(R.string.cancel) } @@ -2843,9 +3023,13 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Get the WebView theme entry values string array. This is done here so that expensive resource requests are not made each time a domain is loaded. webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values) - // Get the user agent array adapter and string array. These are done here so that expensive resource requests are not made each time a domain is loaded. - userAgentNamesArray = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.spinner_item) + // Get the user agent string arrays. These are done here so that expensive resource requests are not made each time a domain is loaded. userAgentDataArray = resources.getStringArray(R.array.user_agent_data) + userAgentNamesArray = resources.getStringArray(R.array.user_agent_names) + + // Get the user agent array adapters. These are done here so that expensive resource requests are not made each time a domain is loaded. + userAgentDataArrayAdapter = ArrayAdapter.createFromResource(this, R.array.user_agent_data, R.layout.spinner_item) + userAgentNamesArrayAdapter = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.spinner_item) // Store the values from the shared preferences in variables. incognitoModeEnabled = sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false) @@ -3198,23 +3382,22 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Set the user agent. if (userAgentName == getString(R.string.system_default_user_agent)) { // Use the system default user agent. // Set the user agent according to the system default. - when (val defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName)) { - // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. - UNRECOGNIZED_USER_AGENT -> nestedScrollWebView.settings.userAgentString = defaultUserAgentName + when (val defaultUserAgentArrayPosition = userAgentNamesArrayAdapter.getPosition(defaultUserAgentName)) { + UNRECOGNIZED_USER_AGENT -> // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. + nestedScrollWebView.settings.userAgentString = defaultUserAgentName - // Set the user agent to `""`, which uses the default value. - SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> nestedScrollWebView.settings.userAgentString = "" + SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> // Set the user agent to `""`, which uses the default value. + nestedScrollWebView.settings.userAgentString = "" - // Set the default custom user agent. - SETTINGS_CUSTOM_USER_AGENT -> nestedScrollWebView.settings.userAgentString = - sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value)) + SETTINGS_CUSTOM_USER_AGENT -> // Set the default custom user agent. + nestedScrollWebView.settings.userAgentString = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value)) - // Get the user agent string from the user agent data array - else -> nestedScrollWebView.settings.userAgentString = userAgentDataArray[defaultUserAgentArrayPosition] + else -> // Get the user agent string from the user agent data array + nestedScrollWebView.settings.userAgentString = userAgentDataArray[defaultUserAgentArrayPosition] } } else { // Set the user agent according to the stored name. // Set the user agent. - when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) { + when (val userAgentArrayPosition = userAgentNamesArrayAdapter.getPosition(userAgentName)) { // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. UNRECOGNIZED_USER_AGENT -> nestedScrollWebView.settings.userAgentString = userAgentName @@ -3285,17 +3468,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // Set the WebView theme. when (webViewThemeInt) { - // Set the WebView theme. - SYSTEM_DEFAULT -> + SYSTEM_DEFAULT -> // Set the WebView theme. when (defaultWebViewTheme) { - // The light theme is selected. Turn off algorithmic darkening. - webViewThemeEntryValuesStringArray[1] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false) + webViewThemeEntryValuesStringArray[1] -> // The light theme is selected. Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false) - // The dark theme is selected. Turn on algorithmic darkening. - webViewThemeEntryValuesStringArray[2] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true) + webViewThemeEntryValuesStringArray[2] -> // The dark theme is selected. Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true) - // The system default theme is selected. - else -> { + else -> { // The system default theme is selected. // Get the current system theme status. val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK @@ -3304,11 +3485,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook } } - // Turn off algorithmic darkening. - LIGHT_THEME -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false) + LIGHT_THEME -> // Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false) - // Turn on algorithmic darkening. - DARK_THEME -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true) + DARK_THEME -> // Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true) } } @@ -3386,33 +3567,31 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook nestedScrollWebView.domainSettingsDatabaseId = -1 // Set the user agent. - when (val userAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName)) { - // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. - UNRECOGNIZED_USER_AGENT -> nestedScrollWebView.settings.userAgentString = defaultUserAgentName + when (val userAgentArrayPosition = userAgentNamesArrayAdapter.getPosition(defaultUserAgentName)) { + UNRECOGNIZED_USER_AGENT -> // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. + nestedScrollWebView.settings.userAgentString = defaultUserAgentName - // Set the user agent to `""`, which uses the default value. - SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> nestedScrollWebView.settings.userAgentString = "" + SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> // Set the user agent to `""`, which uses the default value. + nestedScrollWebView.settings.userAgentString = "" - // Set the default custom user agent. - SETTINGS_CUSTOM_USER_AGENT -> nestedScrollWebView.settings.userAgentString = - sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value)) + SETTINGS_CUSTOM_USER_AGENT -> // Set the default custom user agent. + nestedScrollWebView.settings.userAgentString = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value)) - // Get the user agent string from the user agent data array - else -> nestedScrollWebView.settings.userAgentString = userAgentDataArray[userAgentArrayPosition] + else -> // Get the user agent string from the user agent data array + nestedScrollWebView.settings.userAgentString = userAgentDataArray[userAgentArrayPosition] } // Set the WebView theme if algorithmic darkening is supported. if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // Set the WebView theme. when (defaultWebViewTheme) { - // The light theme is selected. Turn off algorithmic darkening. - webViewThemeEntryValuesStringArray[1] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false) + webViewThemeEntryValuesStringArray[1] -> // The light theme is selected. Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false) - // The dark theme is selected. Turn on algorithmic darkening. - webViewThemeEntryValuesStringArray[2] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true) + webViewThemeEntryValuesStringArray[2] -> // The dark theme is selected. Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true) - // The system default theme is selected. Get the current system theme status. - else -> { + else -> { // The system default theme is selected. Get the current system theme status. // Get the current theme status. val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK @@ -3594,6 +3773,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook } } + private fun calculateSettingsInt(settingCurrentlyEnabled: Boolean, settingEnabledByDefault: Boolean): Int { + return if (settingCurrentlyEnabled == settingEnabledByDefault) // The current system default is used. + SYSTEM_DEFAULT + else if (settingCurrentlyEnabled) // The setting is enabled, which is different from the system default. + ENABLED + else // The setting is disabled, which is different from the system default. + DISABLED + } + private fun clearAndExit() { // Close the bookmarks cursor if it exists. bookmarksCursor?.close() @@ -4003,9 +4191,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Add the first tab. addNewTab("", false) } else { // The activity has been restarted with a saved state. - // Set the current restart time. - restartTime = Date() - // Restore each tab. for (i in savedStateArrayList!!.indices) { // Add a new tab. @@ -4025,21 +4210,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook savedStateArrayList = null savedNestedScrollWebViewStateArrayList = null - // Restore the selected tab position. - if (savedTabPosition == 0) { // The first tab is selected. - // Set the first page as the current WebView. - setCurrentWebView(0) - } else { // The first tab is not selected. - // Select the tab when the layout has finished populating. - tabLayout.post { - // Get a handle for the tab. - val tab = tabLayout.getTabAt(savedTabPosition)!! - - // Select the tab. - tab.select() - } - } - // Get the intent that started the app. val intent = intent @@ -4055,7 +4225,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook val isWebSearch = (intentAction != null) && (intentAction == Intent.ACTION_WEB_SEARCH) // Only process the URI if it contains data or it is a web search. If the user pressed the desktop icon after the app was already running the URI will be null. - if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch) { + if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch) { // A new tab is being loaded. // Get the URL string. val urlString = if (isWebSearch) { // The intent is a web search. // Sanitize the search input. @@ -4083,6 +4253,21 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Make it so. loadUrl(currentWebView!!, urlString) } + } else { // A new tab is not being loaded. + // Restore the selected tab position. + if (savedTabPosition == 0) { // The first tab is selected. + // Set the first page as the current WebView. + setCurrentWebView(0) + } else { // The first tab is not selected. + // Select the tab when the layout has finished populating. + tabLayout.post { + // Get a handle for the tab. + val tab = tabLayout.getTabAt(savedTabPosition)!! + + // Select the tab. + tab.select() + } + } } } } @@ -4219,17 +4404,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Only display the view SSL certificate dialog if the current WebView is not null. // This can happen if the tab is programmatically reselected while the app is being restarted and is not yet populated. if (currentWebView != null) { - // Calculate the milliseconds since the last restart. This can be replaced by the simpler LocalDateTime once the minimum API >= 26. - val millisecondsSinceLastRestart = Date().time - restartTime.time + // Instantiate the View SSL Certificate dialog. + val viewSslCertificateDialogFragment: DialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView!!.webViewFragmentId, currentWebView!!.getFavoriteIcon()) - // Only display the SSL certificate dialog if it has been at least 3 seconds since the last restart as deep restarts sometimes end up selecting a tab twice. - if (millisecondsSinceLastRestart > 3000) { - // Instantiate the View SSL Certificate dialog. - val viewSslCertificateDialogFragment: DialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView!!.webViewFragmentId, currentWebView!!.getFavoriteIcon()) - - // Display the View SSL Certificate dialog. - viewSslCertificateDialogFragment.show(supportFragmentManager, getString(R.string.view_ssl_certificate)) - } + // Display the View SSL Certificate dialog. + viewSslCertificateDialogFragment.show(supportFragmentManager, getString(R.string.view_ssl_certificate)) } } }) @@ -4435,9 +4614,28 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook if (newState == DrawerLayout.STATE_SETTLING || newState == DrawerLayout.STATE_DRAGGING) { // A drawer is opening or closing. // Update the navigation menu items if the WebView is not null. if (currentWebView != null) { + // Set the enabled status of the menu items. navigationBackMenuItem.isEnabled = currentWebView!!.canGoBack() navigationForwardMenuItem.isEnabled = currentWebView!!.canGoForward() + navigationScrollToBottomMenuItem.isEnabled = (currentWebView!!.canScrollVertically(-1) || currentWebView!!.canScrollVertically(1)) navigationHistoryMenuItem.isEnabled = currentWebView!!.canGoBack() || currentWebView!!.canGoForward() + + // Update the scroll menu item. + if (currentWebView!!.scrollY == 0) { // The WebView is scrolled to the top. + // Set the title. + navigationScrollToBottomMenuItem.title = getString(R.string.scroll_to_bottom) + + // Set the icon. + navigationScrollToBottomMenuItem.icon = AppCompatResources.getDrawable(applicationContext, R.drawable.move_down_enabled) + } else { // The WebView is not scrolled to the top. + // Set the title. + navigationScrollToBottomMenuItem.title = getString(R.string.scroll_to_top) + + // Set the icon. + navigationScrollToBottomMenuItem.icon = AppCompatResources.getDrawable(applicationContext, R.drawable.move_up_enabled) + } + + // Display the number of blocked requests. navigationRequestsMenuItem.title = getString(R.string.requests) + " - " + currentWebView!!.getRequestsCount(BLOCKED_REQUESTS) // Hide the keyboard (if displayed). @@ -5659,10 +5857,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook } else { // Load the URL. loadUrl(nestedScrollWebView, urlToLoadString!!) } - - // Reset the intent. This prevents a duplicate tab from being created on a subsequent restart if loading an link from a new intent on restart. - // For example, this prevents a duplicate tab if a link is loaded from the Guide after changing the theme in the guide and then changing the theme again in the main activity. - intent = Intent() } else { // This is not the first tab. // Load the URL. loadUrl(nestedScrollWebView, urlString)