]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebView.java
Implement ad blocking. Fixes https://redmine.stoutner.com/issues/31.
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebView.java
index 345a7060a99a1addc522b33f4c8e8c1782b21794..b9c2746a828aa923e24178784fc8a16afa786345 100644 (file)
@@ -70,6 +70,7 @@ import android.webkit.DownloadListener;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebChromeClient;
+import android.webkit.WebResourceResponse;
 import android.webkit.WebStorage;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
@@ -93,12 +94,18 @@ import com.stoutner.privacybrowser.dialogs.SslCertificateError;
 import com.stoutner.privacybrowser.dialogs.UrlHistory;
 import com.stoutner.privacybrowser.dialogs.ViewSslCertificate;
 
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLEncoder;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 // We need to use AppCompatActivity from android.support.v7.app.AppCompatActivity to have access to the SupportActionBar until the minimum API is >= 21.
 public class MainWebView extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, CreateHomeScreenShortcut.CreateHomeScreenSchortcutListener,
@@ -170,6 +177,9 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
     // `javaScriptEnabledSearchURL` is used in `loadURLFromTextBox()` and `applySettings()`.
     private String javaScriptEnabledSearchURL;
 
+    // `adBlockerEnabled` is used in `onCreate()` and `applySettings()`.
+    private boolean adBlockerEnabled;
+
     // `fullScreenBrowsingModeEnabled` is used in `onCreate()` and `applySettings()`.
     private boolean fullScreenBrowsingModeEnabled;
 
@@ -209,6 +219,9 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
     // `inputMethodManager` is used in `onOptionsItemSelected()`, `loadUrlFromTextBox()`, and `closeFindOnPage()`.
     private InputMethodManager inputMethodManager;
 
+    // `mainWebViewRelativeLayout` is used in `onCreate()` and `onNavigationItemSelected()`.
+    private RelativeLayout mainWebViewRelativeLayout;
+
     @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.
     @SuppressLint("SetJavaScriptEnabled")
@@ -256,6 +269,7 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
         // Get handles for views that need to be accessed.
         drawerLayout = (DrawerLayout) findViewById(R.id.drawerlayout);
         rootCoordinatorLayout = (CoordinatorLayout) findViewById(R.id.root_coordinatorlayout);
+        mainWebViewRelativeLayout = (RelativeLayout) findViewById(R.id.main_webview_relativelayout);
         mainWebView = (WebView) findViewById(R.id.mainWebView);
         findOnPageLinearLayout = (LinearLayout) findViewById(R.id.find_on_page_linearlayout);
         findOnPageEditText = (EditText) findViewById(R.id.find_on_page_edittext);
@@ -287,10 +301,10 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
                             // Remove the translucent status bar overlay on the `Drawer Layout`, which is special and needs its own command.
                             drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
 
-                        /* SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
-                         * 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 rehides them after they are shown.
-                         */
+                            /* SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
+                             * 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 rehides them after they are shown.
+                             */
                             rootCoordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
 
                             // Set `rootCoordinatorLayout` to fill the whole screen.
@@ -455,6 +469,28 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
         // drawerToggle creates the hamburger icon at the start of the AppBar.
         drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, supportAppBar, R.string.open_navigation_drawer, R.string.close_navigation_drawer);
 
+        // Initialize `adServerSet`.
+        final Set<String> adServersSet = new HashSet<>();
+
+        // Load the list of ad servers into memory.
+        try {
+            // Load `pgl.yoyo.org_adservers.txt` into a `BufferedReader`.
+            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(getAssets().open("pgl.yoyo.org_adservers.txt")));
+
+            // Create a string for storing each ad server.
+            String adServer;
+
+            // Populate `adServersSet`.
+            while ((adServer = bufferedReader.readLine()) != null) {
+                adServersSet.add(adServer);
+            }
+
+            // Close `bufferedReader`.
+            bufferedReader.close();
+        } catch (IOException ioException) {
+            // We're pretty sure the asset exists, so we don't need to worry about the `IOException` ever being thrown.
+        }
+
         mainWebView.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.
             // We have to use the deprecated `shouldOverrideUrlLoading` until API >= 24.
@@ -481,6 +517,41 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
                 }
             }
 
+            // Block ads.  We have to use the deprecated `shouldInterceptRequest` until minimum API >= 21.
+            @SuppressWarnings("deprecation")
+            @Override
+            public WebResourceResponse shouldInterceptRequest(WebView view, String url){
+                if (adBlockerEnabled) {  // Block ads.
+                    // Extract the host from `url`.
+                    Uri requestUri = Uri.parse(url);
+                    String requestHost = requestUri.getHost();
+
+                    // Create a variable to track if this is an ad server.
+                    boolean requestHostIsAdServer = false;
+
+                    // Check all the subdomains of `requestHost`.
+                    while (requestHost.contains(".")) {
+                        if (adServersSet.contains(requestHost)) {
+                            requestHostIsAdServer = true;
+                        }
+
+                        // Strip out the lowest subdomain of `requestHost`.
+                        requestHost = requestHost.substring(requestHost.indexOf(".") + 1);
+                    }
+
+                    if (requestHostIsAdServer) {  // It is an ad server.
+                        // Return an empty `WebResourceResponse`.
+                        return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
+                    } else {  // It is not an ad server.
+                        // `return null` loads the requested resource.
+                        return null;
+                    }
+                } else {  // Ad blocking is disabled.
+                    // `return null` loads the requested resource.
+                    return null;
+                }
+            }
+
             // Update the URL in urlTextBox when the page starts to load.
             @Override
             public void onPageStarted(WebView view, String url, Bitmap favicon) {
@@ -1150,7 +1221,6 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
                 customHeaders.clear();
 
                 // Detach all views from `mainWebViewRelativeLayout`.
-                RelativeLayout mainWebViewRelativeLayout = (RelativeLayout) findViewById(R.id.mainWebViewRelativeLayout);
                 mainWebViewRelativeLayout.removeAllViews();
 
                 // Destroy the internal state of `mainWebView`.
@@ -1645,6 +1715,7 @@ public class MainWebView extends AppCompatActivity implements NavigationView.OnN
         String homepageString = sharedPreferences.getString("homepage", "https://www.duckduckgo.com");
         String defaultFontSizeString = sharedPreferences.getString("default_font_size", "100");
         swipeToRefreshEnabled = sharedPreferences.getBoolean("swipe_to_refresh_enabled", false);
+        adBlockerEnabled = sharedPreferences.getBoolean("block_ads", true);
         boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", true);
         boolean proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
         fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("enable_full_screen_browsing_mode", false);