]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java
Fix applying domain settings when navigating history. https://redmine.stoutner.com...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / views / NestedScrollWebView.java
index c7e5ade3dee5a2a45dfe5b970bac98c6c10e9a70..f877745580097b4054484118f16db0eb54859ca3 100644 (file)
 package com.stoutner.privacybrowser.views;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
 import android.webkit.WebView;
 
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
 import androidx.core.view.NestedScrollingChild2;
 import androidx.core.view.NestedScrollingChildHelper;
 import androidx.core.view.ViewCompat;
 
+import com.stoutner.privacybrowser.R;
+
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
+import java.util.List;
 
 // NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen).
 public class NestedScrollWebView extends WebView implements NestedScrollingChild2 {
     // These constants identify the blocklists.
     public final static int BLOCKED_REQUESTS = 0;
-    public final static int EASY_LIST_BLOCKED_REQUESTS = 1;
-    public final static int EASY_PRIVACY_BLOCKED_REQUESTS = 2;
-    public final static int FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS = 3;
-    public final static int FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS = 4;
-    public final static int ULTRA_PRIVACY_BLOCKED_REQUESTS = 5;
-    public final static int THIRD_PARTY_BLOCKED_REQUESTS = 6;
+    public final static int EASYLIST = 1;
+    public final static int EASYPRIVACY = 2;
+    public final static int FANBOYS_ANNOYANCE_LIST = 3;
+    public final static int FANBOYS_SOCIAL_BLOCKING_LIST = 4;
+    public final static int ULTRALIST = 5;
+    public final static int ULTRAPRIVACY = 6;
+    public final static int THIRD_PARTY_REQUESTS = 7;
 
     // Keep a copy of the WebView fragment ID.
     private long webViewFragmentId;
 
+    // Store the handlers.
+    private SslErrorHandler sslErrorHandler;
+    private HttpAuthHandler httpAuthHandler;
+
     // Track if domain settings are applied to this nested scroll WebView and, if so, the database ID.
     private boolean domainSettingsApplied;
     private int domainSettingsDatabaseId;
 
+    // Keep track of the current URL.  This is used to not block resource requests to the main URL.
+    private String currentUrl;
+
+    // Keep track of when the domain name changes so that domain settings can be reapplied.  This should never be null.
+    private String currentDomainName = "";
+
+    // Track the status of first-party cookies.
+    private boolean acceptFirstPartyCookies;
+
+    // Track the domain settings JavaScript status.  This can be removed once night mode does not require JavaScript.
+    private boolean domainSettingsJavaScriptEnabled;
+
     // Track the resource requests.
-    private ArrayList<String[]> resourceRequests = new ArrayList<>();
+    private List<String[]> resourceRequests = Collections.synchronizedList(new ArrayList<>());  // Using a synchronized list makes adding resource requests thread safe.
+    private boolean easyListEnabled;
+    private boolean easyPrivacyEnabled;
+    private boolean fanboysAnnoyanceListEnabled;
+    private boolean fanboysSocialBlockingListEnabled;
+    private boolean ultraListEnabled;
+    private boolean ultraPrivacyEnabled;
+    private boolean blockAllThirdPartyRequests;
     private int blockedRequests;
     private int easyListBlockedRequests;
     private int easyPrivacyBlockedRequests;
     private int fanboysAnnoyanceListBlockedRequests;
     private int fanboysSocialBlockingListBlockedRequests;
+    private int ultraListBlockedRequests;
     private int ultraPrivacyBlockedRequests;
     private int thirdPartyBlockedRequests;
 
@@ -81,6 +117,15 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild
     // The ignore pinned domain information tracker.  This is set when a user proceeds past a pinned mismatch dialog to prevent the dialog from showing again until after the domain changes.
     private boolean ignorePinnedDomainInformation;
 
+    // The default or favorite icon.
+    private Bitmap favoriteOrDefaultIcon;
+
+    // Track night mode.
+    private boolean nightMode;
+
+    // Track swipe to refresh.
+    private boolean swipeToRefresh;
+
     // The nested scrolling child helper is used throughout the class.
     private NestedScrollingChildHelper nestedScrollingChildHelper;
 
@@ -127,6 +172,40 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild
     }
 
 
+    // SSL error handler.
+    public void setSslErrorHandler(SslErrorHandler sslErrorHandler) {
+        // Store the current SSL error handler.
+        this.sslErrorHandler = sslErrorHandler;
+    }
+
+    public SslErrorHandler getSslErrorHandler() {
+        // Return the current SSL error handler.
+        return sslErrorHandler;
+    }
+
+    public void resetSslErrorHandler() {
+        // Reset the current SSL error handler.
+        sslErrorHandler = null;
+    }
+
+
+    // HTTP authentication handler.
+    public void setHttpAuthHandler(HttpAuthHandler httpAuthHandler) {
+        // Store the current HTTP authentication handler.
+        this.httpAuthHandler = httpAuthHandler;
+    }
+
+    public HttpAuthHandler getHttpAuthHandler() {
+        // Return the current HTTP authentication handler.
+        return httpAuthHandler;
+    }
+
+    public void resetHttpAuthHandler() {
+        // Reset the current HTTP authentication handler.
+        httpAuthHandler = null;
+    }
+
+
     // Domain settings.
     public void setDomainSettingsApplied(boolean applied) {
         // Store the domain settings applied status.
@@ -151,14 +230,67 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild
     }
 
 
+    // Current URL.
+    public void setCurrentUrl(String url) {
+        // Store the current URL.
+        currentUrl = url;
+    }
+
+    public String getCurrentUrl() {
+        // Return the current URL.
+        return currentUrl;
+    }
+
+
+    // Current domain name.  To function well when called, the domain name should never be allowed to be null.
+    public void setCurrentDomainName(@NonNull String domainName) {
+        // Store the current domain name.
+        currentDomainName = domainName;
+    }
+
+    public void resetCurrentDomainName() {
+        // Reset the current domain name.
+        currentDomainName = "";
+    }
+
+    public String getCurrentDomainName() {
+        // Return the current domain name.
+        return currentDomainName;
+    }
+
+
+    // First-party cookies.
+    public void setAcceptFirstPartyCookies(boolean status) {
+        // Store the accept first-party cookies status.
+        acceptFirstPartyCookies = status;
+    }
+
+    public boolean getAcceptFirstPartyCookies() {
+        // Return the accept first-party cookies status.
+        return acceptFirstPartyCookies;
+    }
+
+
+    // Domain settings JavaScript enabled.  This can be removed once night mode does not require JavaScript.
+    public void setDomainSettingsJavaScriptEnabled(boolean status) {
+        // Store the domain settings JavaScript status.
+        domainSettingsJavaScriptEnabled = status;
+    }
+
+    public boolean getDomainSettingsJavaScriptEnabled() {
+        // Return the domain settings JavaScript status.
+        return domainSettingsJavaScriptEnabled;
+    }
+
+
     // Resource requests.
     public void addResourceRequest(String[] resourceRequest) {
         // Add the resource request to the list.
         resourceRequests.add(resourceRequest);
     }
 
-    public ArrayList<String[]> getResourceRequests() {
-        // Return the list of resource requests.
+    public List<String[]> getResourceRequests() {
+        // Return the list of resource requests as an array list.
         return resourceRequests;
     }
 
@@ -168,115 +300,175 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild
     }
 
 
-    // Resource request counters.
-    public void resetRequestsCount(int list) {
-        // Run the command on the indicated list.
-        switch (list) {
-            case BLOCKED_REQUESTS:
-                // Reset the blocked requests count.
-                blockedRequests = 0;
+    // Blocklists.
+    public void enableBlocklist(int blocklist, boolean status) {
+        // Update the status of the indicated blocklist.
+        switch (blocklist) {
+            case EASYLIST:
+                // Update the status of the blocklist.
+                easyListEnabled = status;
                 break;
 
-            case EASY_LIST_BLOCKED_REQUESTS:
-                // Reset the EasyList blocked requests count.
-                easyListBlockedRequests = 0;
+            case EASYPRIVACY:
+                // Update the status of the blocklist.
+                easyPrivacyEnabled = status;
                 break;
 
-            case EASY_PRIVACY_BLOCKED_REQUESTS:
-                // Reset the EasyPrivacy blocked requests count.
-                easyPrivacyBlockedRequests = 0;
+            case FANBOYS_ANNOYANCE_LIST:
+                // Update the status of the blocklist.
+                fanboysAnnoyanceListEnabled = status;
                 break;
 
-            case FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS:
-                // Reset the Fanboy's Annoyance List blocked requests count.
-                fanboysAnnoyanceListBlockedRequests = 0;
+            case FANBOYS_SOCIAL_BLOCKING_LIST:
+                // Update the status of the blocklist.
+                fanboysSocialBlockingListEnabled = status;
                 break;
 
-            case FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS:
-                // Reset the Fanboy's Social Blocking List blocked requests count.
-                fanboysSocialBlockingListBlockedRequests = 0;
+            case ULTRALIST:
+                // Update the status of the blocklist.
+                ultraListEnabled = status;
                 break;
 
-            case ULTRA_PRIVACY_BLOCKED_REQUESTS:
-                // Reset the UltraPrivacy blocked requests count.
-                ultraPrivacyBlockedRequests = 0;
+            case ULTRAPRIVACY:
+                // Update the status of the blocklist.
+                ultraPrivacyEnabled = status;
                 break;
 
-            case THIRD_PARTY_BLOCKED_REQUESTS:
-                // Reset the Third Party blocked requests count.
-                thirdPartyBlockedRequests = 0;
+            case THIRD_PARTY_REQUESTS:
+                // Update the status of the blocklist.
+                blockAllThirdPartyRequests = status;
                 break;
         }
     }
 
-    public void incrementRequestsCount(int list) {
-        // Run the command on the indicated list.
-        switch (list) {
+    public boolean isBlocklistEnabled(int blocklist) {
+        // Get the status of the indicated blocklist.
+        switch (blocklist) {
+            case EASYLIST:
+                // Return the status of the blocklist.
+                return easyListEnabled;
+
+            case EASYPRIVACY:
+                // Return the status of the blocklist.
+                return easyPrivacyEnabled;
+
+            case FANBOYS_ANNOYANCE_LIST:
+                // Return the status of the blocklist.
+                return fanboysAnnoyanceListEnabled;
+
+            case FANBOYS_SOCIAL_BLOCKING_LIST:
+                // Return the status of the blocklist.
+                return fanboysSocialBlockingListEnabled;
+
+            case ULTRALIST:
+                // Return the status of the blocklist.
+                return ultraListEnabled;
+
+            case ULTRAPRIVACY:
+                // Return the status of the blocklist.
+                return ultraPrivacyEnabled;
+
+            case THIRD_PARTY_REQUESTS:
+                // Return the status of the blocklist.
+                return blockAllThirdPartyRequests;
+
+            default:
+                // The default value is required but should never be used.
+                return false;
+        }
+    }
+
+
+    // Resource request counters.
+    public void resetRequestsCounters() {
+        // Reset all the resource request counters.
+        blockedRequests = 0;
+        easyListBlockedRequests = 0;
+        easyPrivacyBlockedRequests = 0;
+        fanboysAnnoyanceListBlockedRequests = 0;
+        fanboysSocialBlockingListBlockedRequests = 0;
+        ultraListBlockedRequests = 0;
+        ultraPrivacyBlockedRequests = 0;
+        thirdPartyBlockedRequests = 0;
+    }
+
+    public void incrementRequestsCount(int blocklist) {
+        // Increment the count of the indicated blocklist.
+        switch (blocklist) {
             case BLOCKED_REQUESTS:
                 // Increment the blocked requests count.
                 blockedRequests++;
                 break;
 
-            case EASY_LIST_BLOCKED_REQUESTS:
+            case EASYLIST:
                 // Increment the EasyList blocked requests count.
                 easyListBlockedRequests++;
                 break;
 
-            case EASY_PRIVACY_BLOCKED_REQUESTS:
+            case EASYPRIVACY:
                 // Increment the EasyPrivacy blocked requests count.
                 easyPrivacyBlockedRequests++;
                 break;
 
-            case FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS:
+            case FANBOYS_ANNOYANCE_LIST:
                 // Increment the Fanboy's Annoyance List blocked requests count.
                 fanboysAnnoyanceListBlockedRequests++;
                 break;
 
-            case FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS:
+            case FANBOYS_SOCIAL_BLOCKING_LIST:
                 // Increment the Fanboy's Social Blocking List blocked requests count.
                 fanboysSocialBlockingListBlockedRequests++;
                 break;
 
-            case ULTRA_PRIVACY_BLOCKED_REQUESTS:
+            case ULTRALIST:
+                // Increment the UltraList blocked requests count.
+                ultraListBlockedRequests++;
+                break;
+
+            case ULTRAPRIVACY:
                 // Increment the UltraPrivacy blocked requests count.
                 ultraPrivacyBlockedRequests++;
                 break;
 
-            case THIRD_PARTY_BLOCKED_REQUESTS:
+            case THIRD_PARTY_REQUESTS:
                 // Increment the Third Party blocked requests count.
                 thirdPartyBlockedRequests++;
                 break;
         }
     }
 
-    public int getRequestsCount(int list) {
-        // Run the command on the indicated list.
-        switch (list) {
+    public int getRequestsCount(int blocklist) {
+        // Get the count of the indicated blocklist.
+        switch (blocklist) {
             case BLOCKED_REQUESTS:
                 // Return the blocked requests count.
                 return blockedRequests;
 
-            case EASY_LIST_BLOCKED_REQUESTS:
+            case EASYLIST:
                 // Return the EasyList blocked requests count.
                 return easyListBlockedRequests;
 
-            case EASY_PRIVACY_BLOCKED_REQUESTS:
+            case EASYPRIVACY:
                 // Return the EasyPrivacy blocked requests count.
                 return easyPrivacyBlockedRequests;
 
-            case FANBOYS_ANNOYANCE_LIST_BLOCKED_REQUESTS:
+            case FANBOYS_ANNOYANCE_LIST:
                 // Return the Fanboy's Annoyance List blocked requests count.
                 return fanboysAnnoyanceListBlockedRequests;
 
-            case FANBOYS_SOCIAL_BLOCKING_LIST_BLOCKED_REQUESTS:
+            case FANBOYS_SOCIAL_BLOCKING_LIST:
                 // Return the Fanboy's Social Blocking List blocked requests count.
                 return fanboysSocialBlockingListBlockedRequests;
 
-            case ULTRA_PRIVACY_BLOCKED_REQUESTS:
+            case ULTRALIST:
+                // Return the UltraList blocked requests count.
+                return ultraListBlockedRequests;
+
+            case ULTRAPRIVACY:
                 // Return the UltraPrivacy blocked requests count.
                 return ultraPrivacyBlockedRequests;
 
-            case THIRD_PARTY_BLOCKED_REQUESTS:
+            case THIRD_PARTY_REQUESTS:
                 // Return the Third Party blocked requests count.
                 return thirdPartyBlockedRequests;
 
@@ -398,16 +590,84 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild
     }
 
 
-    // Ignore pinned information.  The syntax looks better as written, even if it is always inverted.
+    // Ignore pinned information.
+    public void setIgnorePinnedDomainInformation(boolean status) {
+        // Set the status of the ignore pinned domain information tracker.
+        ignorePinnedDomainInformation = status;
+    }
+
+    // The syntax looks better as written, even if it is always inverted.
     @SuppressWarnings("BooleanMethodIsAlwaysInverted")
     public boolean ignorePinnedDomainInformation() {
         // Return the status of the ignore pinned domain information tracker.
         return ignorePinnedDomainInformation;
     }
 
-    public void setIgnorePinnedDomainInformation(boolean status) {
-        // Set the status of the ignore pinned domain information tracker.
-        ignorePinnedDomainInformation = status;
+
+    // Favorite or default icon.
+    public void initializeFavoriteIcon() {
+        // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
+        Drawable favoriteIconDrawable = ContextCompat.getDrawable(getContext(), R.drawable.world);
+
+        // Cast the favorite icon drawable to a bitmap drawable.
+        BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable;
+
+        // Remove the incorrect warning below that the favorite icon bitmap drawable might be null.
+        assert favoriteIconBitmapDrawable != null;
+
+        // Store the default icon bitmap.
+        favoriteOrDefaultIcon = favoriteIconBitmapDrawable.getBitmap();
+    }
+
+    public void setFavoriteOrDefaultIcon(Bitmap icon) {
+        // Scale the favorite icon bitmap down if it is larger than 256 x 256.  Filtering uses bilinear interpolation.
+        if ((icon.getHeight() > 256) || (icon.getWidth() > 256)) {
+            favoriteOrDefaultIcon = Bitmap.createScaledBitmap(icon, 256, 256, true);
+        } else {
+            // Store the icon as presented.
+            favoriteOrDefaultIcon = icon;
+        }
+    }
+
+    public Bitmap getFavoriteOrDefaultIcon() {
+        // Return the favorite or default icon.
+        return favoriteOrDefaultIcon;
+    }
+
+
+    // Night mode.
+    public void setNightMode(boolean status) {
+        // Store the night mode status.
+        nightMode = status;
+    }
+
+    public boolean getNightMode() {
+        // Return the night mode status.
+        return nightMode;
+    }
+
+
+    // Swipe to refresh.
+    public void setSwipeToRefresh(boolean status) {
+        // Store the swipe to refresh status.
+        swipeToRefresh = status;
+    }
+
+    public boolean getSwipeToRefresh() {
+        // Return the swipe to refresh status.
+        return swipeToRefresh;
+    }
+
+
+    // Scroll range.
+    public int getHorizontalScrollRange() {
+        // Return the horizontal scroll range.
+        return computeHorizontalScrollRange();
+    }
+
+    public int getVerticalScrollRange() {
+        // Return the vertical scroll range.
+        return computeVerticalScrollRange();
     }
 
 
@@ -452,12 +712,13 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild
                 // Dispatch the nested pre-school.  This scrolls the app bar if it needs it.  `offsetInWindow` will be returned with an updated value.
                 if (dispatchNestedPreScroll(0, preScrollDeltaY, consumedScroll, offsetInWindow)) {
                     // Update the scroll delta Y if some of it was consumed.
+                    // There is currently a bug in Android where if scrolling up at a certain slow speed the input can lock the pre scroll and continue to consume it after the app bar is fully displayed.
                     scrollDeltaY = preScrollDeltaY - consumedScroll[1];
                 }
 
                 // Check to see if the WebView is at the top and and the scroll action is downward.
                 if ((webViewYPosition == 0) && (scrollDeltaY < 0)) {  // Swipe to refresh is being engaged.
-                    // Stop the nested scroll so that swipe to refresh has complete control.
+                    // Stop the nested scroll so that swipe to refresh has complete control.  This way releasing the scroll to refresh circle doesn't scroll the WebView at the same time.
                     stopNestedScroll();
                 } else {  // Swipe to refresh is not being engaged.
                     // Start the nested scroll so that the app bar can scroll off the screen.