]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
Fix custom headers not being loaded for links initialed from the WebView. https...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.java
index becbd5ac8ab5fd55ed65b6305196082fd87518f4..be28dd88489c516c2d48549f37f7db1b7d07b011 100644 (file)
@@ -107,6 +107,8 @@ import androidx.drawerlayout.widget.DrawerLayout;
 import androidx.fragment.app.DialogFragment;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 import androidx.viewpager.widget.ViewPager;
+import androidx.webkit.WebSettingsCompat;
+import androidx.webkit.WebViewFeature;
 
 import com.google.android.material.appbar.AppBarLayout;
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -3732,10 +3734,7 @@ 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.
     @SuppressLint("SetJavaScriptEnabled")
-    private boolean applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetTab, boolean reloadWebsite) {
-        // Store a copy of the current user agent to track changes for the return boolean.
-        String initialUserAgent = nestedScrollWebView.getSettings().getUserAgentString();
-
+    private void applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetTab, boolean reloadWebsite) {
         // Store the current URL.
         nestedScrollWebView.setCurrentUrl(url);
 
@@ -4050,23 +4049,29 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         // Store the swipe to refresh status in the nested scroll WebView.
                         nestedScrollWebView.setSwipeToRefresh(defaultSwipeToRefresh);
 
-                        // Apply swipe to refresh according to the default.  This can be removed once the minimum API >= 23 because it is continuously set by an on scroll change listener.
-                        swipeRefreshLayout.setEnabled(defaultSwipeToRefresh);
+                        // Update the swipe refresh layout.
+                        if (defaultSwipeToRefresh) {  // Swipe to refresh is enabled.
+                            // Only enable the swipe refresh layout if the WebView is scrolled to the top.  It is updated every time the scroll changes.
+                            swipeRefreshLayout.setEnabled(currentWebView.getY() == 0);
+                        } else {  // Swipe to refresh is disabled.
+                            // Disable the swipe refresh layout.
+                            swipeRefreshLayout.setEnabled(false);
+                        }
                         break;
 
                     case DomainsDatabaseHelper.ENABLED:
                         // Store the swipe to refresh status in the nested scroll WebView.
                         nestedScrollWebView.setSwipeToRefresh(true);
 
-                        // Enable swipe to refresh.  This can be removed once the minimum API >= 23 because it is continuously set by an on scroll change listener.
-                        swipeRefreshLayout.setEnabled(true);
+                        // Only enable the swipe refresh layout if the WebView is scrolled to the top.  It is updated every time the scroll changes.
+                        swipeRefreshLayout.setEnabled(currentWebView.getY() == 0);
                         break;
 
                     case DomainsDatabaseHelper.DISABLED:
                         // Store the swipe to refresh status in the nested scroll WebView.
                         nestedScrollWebView.setSwipeToRefresh(false);
 
-                        // Disable swipe to refresh.  This can be removed once the minimum API >= 23 because it is continuously set by an on scroll change listener.
+                        // Disable swipe to refresh.
                         swipeRefreshLayout.setEnabled(false);
                 }
 
@@ -4154,8 +4159,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 // Store the swipe to refresh status in the nested scroll WebView.
                 nestedScrollWebView.setSwipeToRefresh(defaultSwipeToRefresh);
 
-                // Apply swipe to refresh according to the default.
-                swipeRefreshLayout.setEnabled(defaultSwipeToRefresh);
+                // Update the swipe refresh layout.
+                if (defaultSwipeToRefresh) {  // Swipe to refresh is enabled.
+                    // Only enable the swipe refresh layout if the WebView is scrolled to the top.  It is updated every time the scroll changes.
+                    swipeRefreshLayout.setEnabled(currentWebView.getY() == 0);
+                } else {  // Swipe to refresh is disabled.
+                    // Disable the swipe refresh layout.
+                    swipeRefreshLayout.setEnabled(false);
+                }
 
                 // Reset the pinned variables.
                 nestedScrollWebView.setDomainSettingsDatabaseId(-1);
@@ -4211,9 +4222,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         if (reloadWebsite) {
             nestedScrollWebView.reload();
         }
-
-        // Return the user agent changed status.
-        return !nestedScrollWebView.getSettings().getUserAgentString().equals(initialUserAgent);
     }
 
     private void applyProxy(boolean reloadWebViews) {
@@ -5176,26 +5184,60 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         });
 
         // Update the status of swipe to refresh based on the scroll position of the nested scroll WebView.  Also reinforce full screen browsing mode.
-        // Once the minimum API >= 23 this can be replaced with `nestedScrollWebView.setOnScrollChangeListener()`.
-        nestedScrollWebView.getViewTreeObserver().addOnScrollChangedListener(() -> {
-            if (nestedScrollWebView.getSwipeToRefresh()) {
-                // Only enable swipe to refresh if the WebView is scrolled to the top.
-                swipeRefreshLayout.setEnabled(nestedScrollWebView.getScrollY() == 0);
-            }
+        // On API < 23, `getViewTreeObserver().addOnScrollChangedListener()` must be used, but it is a little bit buggy and appears to get garbage collected from time to time.
+        if (Build.VERSION.SDK_INT >= 23) {
+            nestedScrollWebView.setOnScrollChangeListener((view, i, i1, i2, i3) -> {
+                if (nestedScrollWebView.getSwipeToRefresh()) {
+                    // Only enable swipe to refresh if the WebView is scrolled to the top.
+                    swipeRefreshLayout.setEnabled(nestedScrollWebView.getScrollY() == 0);
+                } else {
+                    // Disable swipe to refresh.
+                    swipeRefreshLayout.setEnabled(false);
+                }
+
+                // Reinforce the system UI visibility flags if in full screen browsing mode.
+                // This hides the status and navigation bars, which are displayed if other elements are shown, like dialog boxes, the options menu, or the keyboard.
+                if (inFullScreenBrowsingMode) {
+                    /* Hide the system bars.
+                     * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
+                     * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar.
+                     * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
+                     * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
+                     */
+                    rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+                            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+                }
+            });
+        } else {
+            nestedScrollWebView.getViewTreeObserver().addOnScrollChangedListener(() -> {
+                if (nestedScrollWebView.getSwipeToRefresh()) {
+                    // Only enable swipe to refresh if the WebView is scrolled to the top.
+                    swipeRefreshLayout.setEnabled(nestedScrollWebView.getScrollY() == 0);
+                } else {
+                    // Disable swipe to refresh.
+                    swipeRefreshLayout.setEnabled(false);
+                }
 
-            // Reinforce the system UI visibility flags if in full screen browsing mode.
-            // This hides the status and navigation bars, which are displayed if other elements are shown, like dialog boxes, the options menu, or the keyboard.
-            if (inFullScreenBrowsingMode) {
-                /* Hide the system bars.
-                 * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
-                 * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar.
-                 * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
-                 * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
-                 */
-                rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
-                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-            }
-        });
+
+                // Reinforce the system UI visibility flags if in full screen browsing mode.
+                // This hides the status and navigation bars, which are displayed if other elements are shown, like dialog boxes, the options menu, or the keyboard.
+                if (inFullScreenBrowsingMode) {
+                    /* Hide the system bars.
+                     * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
+                     * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar.
+                     * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
+                     * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
+                     */
+                    rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+                            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+                }
+            });
+        }
+
+        // TODO.
+        if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
+            WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_AUTO);
+        }
 
         // Set the web chrome client.
         nestedScrollWebView.setWebChromeClient(new WebChromeClient() {
@@ -5450,28 +5492,24 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         });
 
         nestedScrollWebView.setWebViewClient(new WebViewClient() {
-            // `shouldOverrideUrlLoading` makes this `WebView` the default handler for URLs inside the app, so that links are not kicked out to other apps.
+            // `shouldOverrideUrlLoading` makes this WebView the default handler for URLs inside the app, so that links are not kicked out to other apps.
             // The deprecated `shouldOverrideUrlLoading` must be used until API >= 24.
             @Override
             public boolean shouldOverrideUrlLoading(WebView view, String url) {
                 // Sanitize the url.
                 url = sanitizeUrl(url);
 
+                // Handle the URL according to the type.
                 if (url.startsWith("http")) {  // Load the URL in Privacy Browser.
                     // Apply the domain settings for the new URL.  This doesn't do anything if the domain has not changed.
-                    boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false);
+                    applyDomainSettings(nestedScrollWebView, url, true, false);
 
-                    // Check if the user agent has changed.
-                    if (userAgentChanged) {
-                        // Manually load the URL.  The changing of the user agent will cause WebView to reload the previous URL.
-                        nestedScrollWebView.loadUrl(url, customHeaders);
+                    // Manually load the URL.  The changing of the user agent will cause WebView to reload the previous URL.
+                    nestedScrollWebView.loadUrl(url, customHeaders);
 
-                        // Returning true indicates that Privacy Browser is manually handling the loading of the URL.
-                        return true;
-                    } else {
-                        // Returning false causes the current WebView to handle the URL and prevents it from adding redirects to the history list.
-                        return false;
-                    }
+                    // Returning true indicates that Privacy Browser is manually handling the loading of the URL.
+                    // Custom headers cannot be added if false is returned and the WebView handles the loading of the URL.
+                    return true;
                 } else if (url.startsWith("mailto:")) {  // Load the email address in an external email program.
                     // Use `ACTION_SENDTO` instead of `ACTION_SEND` so that only email programs are launched.
                     Intent emailIntent = new Intent(Intent.ACTION_SENDTO);