]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt
Use the secret built-in View Source. https://redmine.stoutner.com/issues/1023
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.kt
index 0dab90f19e458e0414bb153bf1eeaf182930867e..c6d91350ea3a2116eca251efa663e3bbd276749f 100644 (file)
@@ -321,6 +321,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     private lateinit var optionsUserAgentSafariOnIosMenuItem: MenuItem
     private lateinit var optionsUserAgentSafariOnMacosMenuItem: MenuItem
     private lateinit var optionsUserAgentWebViewDefaultMenuItem: MenuItem
+    private lateinit var optionsViewSourceMenuItem: MenuItem
     private lateinit var optionsWideViewportMenuItem: MenuItem
     private lateinit var proxyHelper: ProxyHelper
     private lateinit var redColorSpan: ForegroundColorSpan
@@ -685,6 +686,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
                         // Go back.
                         currentWebView!!.goBack()
+
+                        // Update the URL edit text after a delay.
+                        updateUrlEditTextAfterDelay()
                     } else {  // Close the current tab.
                         // A view is required because the method is also called by an XML `onClick`.
                         closeTab(null)
@@ -774,7 +778,7 @@ 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 at the new tab will be the tab position that is restored.
+            // 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
 
@@ -999,6 +1003,23 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         super.onDestroy()
     }
 
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        // Run the default commands.
+        super.onConfigurationChanged(newConfig)
+
+        // Get the current page.
+        val currentPage = webViewViewPager2.currentItem
+
+        // Toggle the pages if there is more than one so that the view pager will recalculate their size.
+        if (currentPage > 0) {
+            // Switch to the previous page.
+            webViewViewPager2.currentItem = (currentPage - 1)
+
+            // Switch back to the current page after the view pager has quiesced.
+            webViewViewPager2.post { webViewViewPager2.currentItem = currentPage }
+        }
+    }
+
     override fun onCreateOptionsMenu(menu: Menu): Boolean {
         // Inflate the menu.  This adds items to the app bar if it is present.
         menuInflater.inflate(R.menu.webview_options_menu, menu)
@@ -1046,6 +1067,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         optionsDisplayImagesMenuItem = menu.findItem(R.id.display_images)
         optionsDarkWebViewMenuItem = menu.findItem(R.id.dark_webview)
         optionsFontSizeMenuItem = menu.findItem(R.id.font_size)
+        optionsViewSourceMenuItem = menu.findItem(R.id.view_source)
         optionsAddOrEditDomainMenuItem = menu.findItem(R.id.add_or_edit_domain)
 
         // Set the initial status of the privacy icons.  `false` does not call `invalidateOptionsMenu` as the last step.
@@ -1058,9 +1080,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Disable the clear form data menu item if the API >= 26 so that the status of the main Clear Data is calculated correctly.
         optionsClearFormDataMenuItem.isEnabled = Build.VERSION.SDK_INT < 26
 
-        // Only display the dark WebView menu item if the API >= 29.
-        optionsDarkWebViewMenuItem.isVisible = Build.VERSION.SDK_INT >= 29
-
         // Set the status of the additional app bar icons.  Setting the refresh menu item to `SHOW_AS_ACTION_ALWAYS` makes it appear even on small devices like phones.
         if (displayAdditionalAppBarIcons) {  // Display the additional icons.
             optionsRefreshMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
@@ -1123,7 +1142,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             optionsWideViewportMenuItem.isChecked = currentWebView!!.settings.useWideViewPort
             optionsDisplayImagesMenuItem.isChecked = currentWebView!!.settings.loadsImagesAutomatically
 
-            // Initialize the display names for the filter lists with the number of blocked requests.
+            // Set the display names for the filter lists with the number of blocked requests.
             optionsFilterListsMenuItem.title = getString(R.string.filterlists) + " - " + currentWebView!!.getRequestsCount(BLOCKED_REQUESTS)
             optionsEasyListMenuItem.title = currentWebView!!.getRequestsCount(EASYLIST).toString() + " - " + getString(R.string.easylist)
             optionsEasyPrivacyMenuItem.title = currentWebView!!.getRequestsCount(EASYPRIVACY).toString() + " - " + getString(R.string.easyprivacy)
@@ -1142,9 +1161,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             // Enable dark WebView if night mode is enabled.
             optionsDarkWebViewMenuItem.isEnabled = (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES)
 
-            // Set the checkbox status for dark WebView if the device is running API >= 29 and algorithmic darkening is supported.
-            if ((Build.VERSION.SDK_INT >= 29) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING))
+            // Set the checkbox status for dark WebView if algorithmic darkening is supported.
+            if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING))
                 optionsDarkWebViewMenuItem.isChecked = WebSettingsCompat.isAlgorithmicDarkeningAllowed(currentWebView!!.settings)
+
+            // Set the view source title according to the current URL.
+            if (currentWebView!!.currentUrl.startsWith("view-source:"))
+                optionsViewSourceMenuItem.title = getString(R.string.view_rendered_website)
+            else
+                optionsViewSourceMenuItem.title = getString(R.string.view_source)
         }
 
         // Set the cookies menu item checked status.
@@ -1901,7 +1926,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
             R.id.dark_webview -> {  // Dark WebView.
                 // Toggle dark WebView if supported.
-                if ((Build.VERSION.SDK_INT >= 29) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING))
+                if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING))
                     WebSettingsCompat.setAlgorithmicDarkeningAllowed(currentWebView!!.settings, !WebSettingsCompat.isAlgorithmicDarkeningAllowed(currentWebView!!.settings)
                 )
 
@@ -1989,15 +2014,29 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             }
 
             R.id.view_source -> {  // View source.
-                // Create an intent to launch the view source activity.
-                val viewSourceIntent = Intent(this, ViewSourceActivity::class.java)
+                // Open a new tab according to the current URL.
+                if (currentWebView!!.currentUrl.startsWith("view-source:")) {  // The source is currently viewed.
+                    // Open the rendered website in a new tab.
+                    addNewTab(currentWebView!!.currentUrl.substring(12, currentWebView!!.currentUrl.length), true)
+                } else {  // The rendered website is currently viewed.
+                    // Open the source in a new tab.
+                    addNewTab("view-source:${currentWebView!!.currentUrl}", true)
+                }
+
+                // Consume the event.
+                true
+            }
+
+            R.id.view_headers -> {  // View headers.
+                // Create an intent to launch the view headers activity.
+                val viewHeadersIntent = Intent(this, ViewHeadersActivity::class.java)
 
                 // Add the variables to the intent.
-                viewSourceIntent.putExtra(CURRENT_URL, currentWebView!!.url)
-                viewSourceIntent.putExtra(USER_AGENT, currentWebView!!.settings.userAgentString)
+                viewHeadersIntent.putExtra(CURRENT_URL, currentWebView!!.url)
+                viewHeadersIntent.putExtra(USER_AGENT, currentWebView!!.settings.userAgentString)
 
                 // Make it so.
-                startActivity(viewSourceIntent)
+                startActivity(viewHeadersIntent)
 
                 // Consume the event.
                 true
@@ -2195,6 +2234,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
                     // Load the previous website in the history.
                     currentWebView!!.goBack()
+
+                    // Update the URL edit text after a delay.
+                    updateUrlEditTextAfterDelay()
                 }
             }
 
@@ -2212,6 +2254,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
                     // Load the next website in the history.
                     currentWebView!!.goForward()
+
+                    // Update the URL edit text after a delay.
+                    updateUrlEditTextAfterDelay()
                 }
             }
 
@@ -3221,8 +3266,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     }
                 }
 
-                // Set the WebView theme if device is running API >= 29 and algorithmic darkening is supported.
-                if ((Build.VERSION.SDK_INT >= 29) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
+                // Set the WebView theme if algorithmic darkening is supported.
+                if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
                     // Set the WebView theme.
                     when (webViewThemeInt) {
                         // Set the WebView theme.
@@ -3341,8 +3386,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     else -> nestedScrollWebView.settings.userAgentString = userAgentDataArray[userAgentArrayPosition]
                 }
 
-                // Set the WebView theme if the device is running API >= 29 and algorithmic darkening is supported.
-                if ((Build.VERSION.SDK_INT >= 29) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
+                // 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.
@@ -3380,6 +3425,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         if (reloadWebsite)
             nestedScrollWebView.reload()
 
+        // Disable the wide viewport if the source is being viewed.
+        if (url.startsWith("view-source:"))
+            nestedScrollWebView.settings.useWideViewPort = false
+
         // Load the URL if directed.  This makes sure that the domain settings are properly loaded before the URL.  By using `loadUrl()`, instead of `loadUrlFromBase()`, the Referer header will never be sent.
         if (loadUrl)
             nestedScrollWebView.loadUrl(url)
@@ -3968,17 +4017,12 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Set the first page as the current WebView.
                 setCurrentWebView(0)
             } else {  // The first tab is not selected.
-                // Create a handler move to the page.
-                val setCurrentPageHandler = Handler(Looper.getMainLooper())
-
-                // Create a runnable to move to the page.
-                val setCurrentPageRunnable = Runnable {
-                    // Move to the page.
-                    webViewViewPager2.currentItem = savedTabPosition
-                }
+                // Switch to the page before the saved tab position.
+                webViewViewPager2.post { webViewViewPager2.currentItem = (savedTabPosition - 1) }
 
-                // Move to the page after 50 milliseconds, which should be enough time to for the WebView state adapter to populate the restored pages.
-                setCurrentPageHandler.postDelayed(setCurrentPageRunnable, 50)
+                // Switch to the saved tab position.
+                // This has to be done twice because, for some reason, if the above step is skipped there is some race condition where nothing happens and the first page is displayed.
+                webViewViewPager2.post { webViewViewPager2.currentItem = savedTabPosition }
             }
 
             // Get the intent that started the app.
@@ -4426,8 +4470,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Get the WebView theme entry values string array.
         val webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
 
-        // Set the WebView theme if device is running API >= 29 and algorithmic darkening is supported.
-        if (Build.VERSION.SDK_INT >= 29 && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
+        // Set the WebView theme if algorithmic darkening is supported.
+        if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
             // Set the WebView them.  A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant.
             if (webViewTheme == webViewThemeEntryValuesStringArray[1]) {  // The light theme is selected.
                 // Turn off algorithmic darkening.
@@ -5337,8 +5381,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
                 // Update the URL text bar if the page is currently selected and the URL edit text is not currently being edited.
                 if ((tabLayout.selectedTabPosition == currentPagePosition) && !urlEditText.hasFocus()) {
-                    // Display the formatted URL text.
-                    urlEditText.setText(url)
+                    // Display the formatted URL text.  The nested scroll WebView current URL preserves any initial `view-source:`, and opposed to the method URL variable.
+                    urlEditText.setText(nestedScrollWebView.currentUrl)
 
                     // Highlight the URL syntax.
                     UrlHelper.highlightSyntax(urlEditText, initialGrayColorSpan, finalGrayColorSpan, redColorSpan)
@@ -5680,7 +5724,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         var urlString = ""
 
         // Check to see if the unformatted URL string is a valid URL.  Otherwise, convert it into a search.
-        if (unformattedUrlString.startsWith("content://")) {  // This is a content URL.
+        if (unformattedUrlString.startsWith("content://") || unformattedUrlString.startsWith("view-source:")) {  // This is a content or source URL.
             // Load the entire content URL.
             urlString = unformattedUrlString
         } else if (Patterns.WEB_URL.matcher(unformattedUrlString).matches() || unformattedUrlString.startsWith("http://") || unformattedUrlString.startsWith("https://") ||
@@ -5744,6 +5788,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
         // Load the history entry.
         currentWebView!!.goBackOrForward(steps)
+
+        // Update the URL edit text after a delay.
+        updateUrlEditTextAfterDelay()
     }
 
     override fun openFile(dialogFragment: DialogFragment) {
@@ -5854,6 +5901,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
         // Go back.
         currentWebView!!.goBack()
+
+        // Update the URL edit text after a delay.
+        updateUrlEditTextAfterDelay()
     }
 
     private fun sanitizeUrl(urlString: String): String {
@@ -6073,4 +6123,22 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 invalidateOptionsMenu()
         }
     }
+
+    fun updateUrlEditTextAfterDelay() {
+        // Create a handler to update the URL edit box.
+        val urlEditTextUpdateHandler = Handler(Looper.getMainLooper())
+
+        // Create a runnable to update the URL edit box.
+        val urlEditTextUpdateRunnable = Runnable {
+            // Update the URL edit text.
+            urlEditText.setText(currentWebView!!.url)
+
+            // Disable the wide viewport if the source is being viewed.
+            if (currentWebView!!.url!!.startsWith("view-source:"))
+                currentWebView!!.settings.useWideViewPort = false
+        }
+
+        // Update the URL edit text after 50 milliseconds, so that the WebView has enough time to navigate to the new URL.
+        urlEditTextUpdateHandler.postDelayed(urlEditTextUpdateRunnable, 50)
+    }
 }