Add controls for displaying webpage images. Implements https://redmine.stoutner...
authorSoren Stoutner <soren@stoutner.com>
Thu, 25 May 2017 04:25:49 +0000 (21:25 -0700)
committerSoren Stoutner <soren@stoutner.com>
Thu, 25 May 2017 04:25:49 +0000 (21:25 -0700)
19 files changed:
app/src/main/assets/de/about_licenses.html
app/src/main/assets/en/about_licenses.html
app/src/main/assets/en/images/ic_image.png [new file with mode: 0644]
app/src/main/assets/es/about_licenses.html
app/src/main/assets/it/about_licenses.html
app/src/main/assets/zh-rTW/about_licenses.html
app/src/main/java/com/stoutner/privacybrowser/activities/DomainSettingsActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/SettingsActivity.java
app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java
app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java
app/src/main/res/drawable/images_disabled.xml [new file with mode: 0644]
app/src/main/res/drawable/images_enabled.xml [new file with mode: 0644]
app/src/main/res/layout/domain_settings.xml
app/src/main/res/menu/webview_options_menu.xml
app/src/main/res/values/strings.xml
app/src/main/res/xml/preferences.xml

index 6b479aeac61198d448b3d6ec42c3fbe2a251e8a8..8f99162a2cd5314e9c4645c104986ce219eb02ba 100644 (file)
@@ -90,6 +90,7 @@
         <p><img class="icon" src="../en/images/ic_folder_special.png"> ic_folder_special.</p>
         <p><img class="icon" src="../en/images/ic_fullscreen.png"> ic_fullscreen.</p>
         <p><img class="icon" src="../en/images/ic_home.png"> ic_home.</p>
+        <p><img class="icon" src="../en/images/ic_image.png"> ic_image.</p>
         <p><img class="icon" src="../en/images/ic_import_contacts.png"> ic_import_contacts.</p>
         <p><img class="icon" src="../en/images/ic_important_devices.png"> ic_important_devices.</p>
         <p><img class="icon" src="../en/images/ic_info_outline.png"> ic_info_outline.</p>
index 4e9f8f660b74a6c0dbd1037578983b06717d3186..01ebe5d19bc69ddb54c61f47bcbe1fd069d4a76c 100644 (file)
@@ -84,6 +84,7 @@
         <p><img class="icon" src="images/ic_folder_special.png"> ic_folder_special.</p>
         <p><img class="icon" src="images/ic_fullscreen.png"> ic_fullscreen.</p>
         <p><img class="icon" src="images/ic_home.png"> ic_home.</p>
+        <p><img class="icon" src="images/ic_image.png"> ic_image.</p>
         <p><img class="icon" src="images/ic_import_contacts.png"> ic_import_contacts.</p>
         <p><img class="icon" src="images/ic_important_devices.png"> ic_important_devices.</p>
         <p><img class="icon" src="images/ic_info_outline.png"> ic_info_outline.</p>
diff --git a/app/src/main/assets/en/images/ic_image.png b/app/src/main/assets/en/images/ic_image.png
new file mode 100644 (file)
index 0000000..3e4dc0c
Binary files /dev/null and b/app/src/main/assets/en/images/ic_image.png differ
index b34a68f3a4c390f41c489dc9ead86ed0137e239a..220c15ee96f37fa07041affd2f0fdb51c4b9eca5 100644 (file)
@@ -46,7 +46,7 @@
 
         <h3>Licencia</h3>
         <p>Navegador Privado está liberado bajo la licencia <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+</a>. El texto completo de la licencia se encuentra en la parte inferior de este documento (se deja en el idioma original).
-            The source code is available from <a href="https://git.stoutner.com/?p=PrivacyBrowser.git;a=summary">git.stoutner.com</a>.</p>
+            El código fuente está disponible en <a href="https://git.stoutner.com/?p=PrivacyBrowser.git;a=summary">git.stoutner.com</a>.</p>
 
         <h3>Atribuciones</h3>
         <p>La lista de servidores publicitarios usados por el bloqueador de anuncios procede de <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
@@ -88,6 +88,7 @@
         <p><img class="icon" src="../en/images/ic_folder_special.png"> ic_folder_special.</p>
         <p><img class="icon" src="../en/images/ic_fullscreen.png"> ic_fullscreen.</p>
         <p><img class="icon" src="../en/images/ic_home.png"> ic_home.</p>
+        <p><img class="icon" src="../en/images/ic_image.png"> ic_image.</p>
         <p><img class="icon" src="../en/images/ic_import_contacts.png"> ic_import_contacts.</p>
         <p><img class="icon" src="../en/images/ic_important_devices.png"> ic_important_devices.</p>
         <p><img class="icon" src="../en/images/ic_info_outline.png"> ic_info_outline.</p>
index eeae2d53316435a90fc33de39edc1394a8357dec..2612a65c3351f0417a2fa7105cc53be5cbb073ab 100644 (file)
@@ -90,6 +90,7 @@
         <p><img class="icon" src="../en/images/ic_folder_special.png"> ic_folder_special.</p>
         <p><img class="icon" src="../en/images/ic_fullscreen.png"> ic_fullscreen.</p>
         <p><img class="icon" src="../en/images/ic_home.png"> ic_home.</p>
+        <p><img class="icon" src="../en/images/ic_image.png"> ic_image.</p>
         <p><img class="icon" src="../en/images/ic_import_contacts.png"> ic_import_contacts.</p>
         <p><img class="icon" src="../en/images/ic_important_devices.png"> ic_important_devices.</p>
         <p><img class="icon" src="../en/images/ic_info_outline.png"> ic_info_outline.</p>
index 0af91d73ec03b4a52b3395ec57e04f00037f7dc4..9b32ce200b6502ba00ad987087b16e8d2acb0365 100644 (file)
@@ -84,6 +84,7 @@
         <p><img class="icon" src="../en/images/ic_folder_special.png"> ic_folder_special.</p>
         <p><img class="icon" src="../en/images/ic_fullscreen.png"> ic_fullscreen.</p>
         <p><img class="icon" src="../en/images/ic_home.png"> ic_home.</p>
+        <p><img class="icon" src="../en/images/ic_image.png"> ic_image.</p>
         <p><img class="icon" src="../en/images/ic_import_contacts.png"> ic_import_contacts.</p>
         <p><img class="icon" src="../en/images/ic_important_devices.png"> ic_important_devices.</p>
         <p><img class="icon" src="../en/images/ic_info_outline.png"> ic_info_outline.</p>
index ccb444a7fc8fea3269e594f5fd0cfb4872daf5c3..49364db391fde22c76b1156d4e4e3ccfde974b21 100644 (file)
@@ -22,7 +22,6 @@ package com.stoutner.privacybrowser.activities;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
-import android.support.design.widget.BaseTransientBottomBar;
 import android.support.design.widget.CoordinatorLayout;
 import android.support.design.widget.Snackbar;
 import android.support.v4.app.NavUtils;
@@ -111,20 +110,22 @@ public class DomainSettingsActivity extends AppCompatActivity {
                 Spinner userAgentSpinner = (Spinner) findViewById(R.id.domain_settings_user_agent_spinner);
                 EditText customUserAgentEditText = (EditText) findViewById(R.id.domain_settings_custom_user_agent_edittext);
                 Spinner fontSizeSpinner = (Spinner) findViewById(R.id.domain_settings_font_size_spinner);
+                Spinner displayWebpageImagesSpinner = (Spinner) findViewById(R.id.domain_settings_display_webpage_images_spinner);
 
                 // Extract the data for the domain settings.
                 String domainNameString = domainNameEditText.getText().toString();
-                boolean javaScriptEnabled = javaScriptEnabledSwitch.isChecked();
-                boolean firstPartyCookiesEnabled = firstPartyCookiesEnabledSwitch.isChecked();
-                boolean thirdPartyCookiesEnabled = thirdPartyCookiesEnabledSwitch.isChecked();
-                boolean domStorageEnabledEnabled = domStorageEnabledSwitch.isChecked();
-                boolean formDataEnabled = formDataEnabledSwitch.isChecked();
-                int userAgentPosition = userAgentSpinner.getSelectedItemPosition();
-                int fontSizePosition = fontSizeSpinner.getSelectedItemPosition();
+                boolean javaScriptEnabledBoolean = javaScriptEnabledSwitch.isChecked();
+                boolean firstPartyCookiesEnabledBoolean = firstPartyCookiesEnabledSwitch.isChecked();
+                boolean thirdPartyCookiesEnabledBoolean = thirdPartyCookiesEnabledSwitch.isChecked();
+                boolean domStorageEnabledEnabledBoolean = domStorageEnabledSwitch.isChecked();
+                boolean formDataEnabledBoolean = formDataEnabledSwitch.isChecked();
+                int userAgentPositionInt = userAgentSpinner.getSelectedItemPosition();
+                int fontSizePositionInt = fontSizeSpinner.getSelectedItemPosition();
+                int displayWebpageImagesInt = displayWebpageImagesSpinner.getSelectedItemPosition();
 
                 // Get the data for the `Spinners` from the entry values string arrays.
-                String userAgentString = getResources().getStringArray(R.array.user_agent_entry_values)[userAgentPosition];
-                int fontSizeInt = Integer.parseInt(getResources().getStringArray(R.array.default_font_size_entry_values)[fontSizePosition]);
+                String userAgentString = getResources().getStringArray(R.array.user_agent_entry_values)[userAgentPositionInt];
+                int fontSizeInt = Integer.parseInt(getResources().getStringArray(R.array.default_font_size_entry_values)[fontSizePositionInt]);
 
                 // Check to see if we are using a custom user agent.
                 if (userAgentString.equals("Custom user agent")) {
@@ -133,7 +134,8 @@ public class DomainSettingsActivity extends AppCompatActivity {
                 }
 
                 // Save the domain settings.
-                domainsDatabaseHelper.saveDomain(databaseId, domainNameString, javaScriptEnabled, firstPartyCookiesEnabled, thirdPartyCookiesEnabled, domStorageEnabledEnabled, formDataEnabled, userAgentString, fontSizeInt);
+                domainsDatabaseHelper.saveDomain(databaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean, formDataEnabledBoolean, userAgentString, fontSizeInt,
+                        displayWebpageImagesInt);
 
                 // Navigate to `DomainsActivity`.
                 NavUtils.navigateUpFromSameTask(this);
index 2500fe9e850739d163bd53589df4d4a399a48d4f..320cddb8e57ebc781b4266db2ad3518a20b91669 100644 (file)
@@ -187,20 +187,22 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                 Spinner userAgentSpinner = (Spinner) findViewById(R.id.domain_settings_user_agent_spinner);
                 EditText customUserAgentEditText = (EditText) findViewById(R.id.domain_settings_custom_user_agent_edittext);
                 Spinner fontSizeSpinner = (Spinner) findViewById(R.id.domain_settings_font_size_spinner);
+                Spinner displayWebpageImagesSpinner = (Spinner) findViewById(R.id.domain_settings_display_webpage_images_spinner);
 
                 // Extract the data for the domain settings.
                 String domainNameString = domainNameEditText.getText().toString();
-                boolean javaScriptEnabled = javaScriptEnabledSwitch.isChecked();
-                boolean firstPartyCookiesEnabled = firstPartyCookiesEnabledSwitch.isChecked();
-                boolean thirdPartyCookiesEnabled = thirdPartyCookiesEnabledSwitch.isChecked();
-                boolean domStorageEnabledEnabled = domStorageEnabledSwitch.isChecked();
-                boolean formDataEnabled = formDataEnabledSwitch.isChecked();
-                int userAgentPosition = userAgentSpinner.getSelectedItemPosition();
-                int fontSizePosition = fontSizeSpinner.getSelectedItemPosition();
+                boolean javaScriptEnabledBoolean = javaScriptEnabledSwitch.isChecked();
+                boolean firstPartyCookiesEnabledBoolean = firstPartyCookiesEnabledSwitch.isChecked();
+                boolean thirdPartyCookiesEnabledBoolean = thirdPartyCookiesEnabledSwitch.isChecked();
+                boolean domStorageEnabledEnabledBoolean  = domStorageEnabledSwitch.isChecked();
+                boolean formDataEnabledBoolean = formDataEnabledSwitch.isChecked();
+                int userAgentPositionInt = userAgentSpinner.getSelectedItemPosition();
+                int fontSizePositionInt = fontSizeSpinner.getSelectedItemPosition();
+                int displayWebpageImagesInt = displayWebpageImagesSpinner.getSelectedItemPosition();
 
                 // Get the data for the `Spinners` from the entry values string arrays.
-                String userAgentString = getResources().getStringArray(R.array.user_agent_entry_values)[userAgentPosition];
-                int fontSizeInt = Integer.parseInt(getResources().getStringArray(R.array.default_font_size_entry_values)[fontSizePosition]);
+                String userAgentString = getResources().getStringArray(R.array.user_agent_entry_values)[userAgentPositionInt];
+                int fontSizeInt = Integer.parseInt(getResources().getStringArray(R.array.default_font_size_entry_values)[fontSizePositionInt]);
 
                 // Check to see if we are using a custom user agent.
                 if (userAgentString.equals("Custom user agent")) {
@@ -209,7 +211,8 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                 }
 
                 // Save the domain settings.
-                domainsDatabaseHelper.saveDomain(databaseId, domainNameString, javaScriptEnabled, firstPartyCookiesEnabled, thirdPartyCookiesEnabled, domStorageEnabledEnabled, formDataEnabled, userAgentString, fontSizeInt);
+                domainsDatabaseHelper.saveDomain(databaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean, formDataEnabledBoolean, userAgentString, fontSizeInt,
+                        displayWebpageImagesInt);
 
                 // Display a `Snackbar`.
                 Snackbar.make(domainsListView, R.string.domain_settings_saved, Snackbar.LENGTH_SHORT).show();
index 01978f46869684e9111240c737353deffa8f65c1..0c80f526d32c53e9aeefc51249479bdbd408a2cd 100644 (file)
@@ -138,6 +138,9 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     // `webViewTitle` is public static so it can be accessed from `CreateBookmarkDialog` and `CreateHomeScreenShortcutDialog`.  It is also used in `onCreate()`.
     public static String webViewTitle;
 
+    // `displayWebpageImagesBoolean` is public static so it can be accessed from `DomainSettingsFragment`.  It is also used in `applyAppSettings` and `applyDomainSettings()`.
+    public static boolean displayWebpageImagesBoolean;
+
 
     // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, and `applyDomainSettings()`.
     private boolean navigatingHistory;
@@ -151,7 +154,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     // `rootCoordinatorLayout` is used in `onCreate()` and `applyAppSettings()`.
     private CoordinatorLayout rootCoordinatorLayout;
 
-    // 'mainWebView' is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, `findNextOnPage()`, `closeFindOnPage()`, and `loadUrlFromTextBox()`.
+    // `mainWebView` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`
+    // and `setDisplayWebpageImages()`.
     private WebView mainWebView;
 
     // `fullScreenVideoFrameLayout` is used in `onCreate()` and `onConfigurationChanged()`.
@@ -218,12 +222,21 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     // `translucentNavigationBarOnFullscreen` is used in `onCreate()` and `applyAppSettings()`.
     private boolean translucentNavigationBarOnFullscreen;
 
-    // `currentDomainName` is used in `onCreate(), `onNavigationItemSelected()`, and `applyDomainSettings()`.
+    // `currentDomainName` is used in `onCreate()`, `onNavigationItemSelected()`, and `applyDomainSettings()`.
     private String currentDomainName;
 
     // `waitingForOrbot` is used in `onCreate()` and `applyAppSettings()`.
     private boolean waitingForOrbot;
 
+    // `domainSettingsApplied` is used in `applyDomainSettings()` and `setDisplayWebpageImages()`.
+    private boolean domainSettingsApplied;
+
+    // `displayWebpageImagesInt` is used in `applyDomainSettings()` and `setDisplayWebpageImages()`.
+    private int displayWebpageImagesInt;
+
+    // `onTheFlyDisplayImagesSet` is used in `applyDomainSettings()` and `setDisplayWebpageImages()`.
+    private boolean onTheFlyDisplayImagesSet;
+
     // `waitingForOrbotData` is used in `onCreate()` and `applyAppSettings()`.
     private String waitingForOrbotHTMLString;
 
@@ -893,6 +906,55 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         }
     }
 
+    @Override
+    public void onRestart() {
+        super.onRestart();
+
+        // Apply the app settings, which may have been changed in `SettingsActivity`.
+        applyAppSettings();
+
+        // Update the privacy icon.  `true` runs `invalidateOptionsMenu` as the last step.
+        updatePrivacyIcons(true);
+
+        // Set the display webpage images mode.
+        setDisplayWebpageImages();
+
+        // Reload the webpage to remove images if `setDisplayWebpageImages` has turned them off.
+        mainWebView.reload();
+    }
+
+    // `onResume()` runs after `onStart()`, which runs after `onCreate()` and `onRestart()`.
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        // Resume JavaScript (if enabled).
+        mainWebView.resumeTimers();
+
+        // Resume `mainWebView`.
+        mainWebView.onResume();
+
+        // Resume the adView for the free flavor.
+        if (BuildConfig.FLAVOR.contentEquals("free")) {
+            BannerAd.resumeAd(adView);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        // Pause `mainWebView`.
+        mainWebView.onPause();
+
+        // Stop all JavaScript.
+        mainWebView.pauseTimers();
+
+        // Pause the adView or it will continue to consume resources in the background on the free flavor.
+        if (BuildConfig.FLAVOR.contentEquals("free")) {
+            BannerAd.pauseAd(adView);
+        }
+
+        super.onPause();
+    }
 
     @Override
     protected void onNewIntent(Intent intent) {
@@ -929,26 +991,26 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         updatePrivacyIcons(false);
 
         // Get handles for the menu items.
-        MenuItem toggleFirstPartyCookies = menu.findItem(R.id.toggleFirstPartyCookies);
-        MenuItem toggleThirdPartyCookies = menu.findItem(R.id.toggleThirdPartyCookies);
-        MenuItem toggleDomStorage = menu.findItem(R.id.toggleDomStorage);
-        MenuItem toggleSaveFormData = menu.findItem(R.id.toggleSaveFormData);
+        MenuItem toggleFirstPartyCookiesMenuItem = menu.findItem(R.id.toggle_first_party_cookies);
+        MenuItem toggleThirdPartyCookiesMenuItem = menu.findItem(R.id.toggle_third_party_cookies);
+        MenuItem toggleDomStorageMenuItem = menu.findItem(R.id.toggle_dom_storage);
+        MenuItem toggleSaveFormDataMenuItem = menu.findItem(R.id.toggle_save_form_data);
 
         // Only display third-party cookies if SDK >= 21
-        toggleThirdPartyCookies.setVisible(Build.VERSION.SDK_INT >= 21);
+        toggleThirdPartyCookiesMenuItem.setVisible(Build.VERSION.SDK_INT >= 21);
 
         // Get the shared preference values.  `this` references the current context.
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
 
         // Set the status of the additional app bar icons.  The default is `false`.
         if (sharedPreferences.getBoolean("display_additional_app_bar_icons", false)) {
-            toggleFirstPartyCookies.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
-            toggleDomStorage.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
-            toggleSaveFormData.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            toggleFirstPartyCookiesMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            toggleDomStorageMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            toggleSaveFormDataMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         } else { //Do not display the additional icons.
-            toggleFirstPartyCookies.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-            toggleDomStorage.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-            toggleSaveFormData.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+            toggleFirstPartyCookiesMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+            toggleDomStorageMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+            toggleSaveFormDataMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         }
 
         return true;
@@ -957,35 +1019,35 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         // Get handles for the menu items.
-        MenuItem toggleFirstPartyCookies = menu.findItem(R.id.toggleFirstPartyCookies);
-        MenuItem toggleThirdPartyCookies = menu.findItem(R.id.toggleThirdPartyCookies);
-        MenuItem toggleDomStorage = menu.findItem(R.id.toggleDomStorage);
-        MenuItem toggleSaveFormData = menu.findItem(R.id.toggleSaveFormData);
-        MenuItem clearCookies = menu.findItem(R.id.clearCookies);
-        MenuItem clearFormData = menu.findItem(R.id.clearFormData);
+        MenuItem toggleFirstPartyCookiesMenuItem = menu.findItem(R.id.toggle_first_party_cookies);
+        MenuItem toggleThirdPartyCookiesMenuItem = menu.findItem(R.id.toggle_third_party_cookies);
+        MenuItem toggleDomStorageMenuItem = menu.findItem(R.id.toggle_dom_storage);
+        MenuItem toggleSaveFormDataMenuItem = menu.findItem(R.id.toggle_save_form_data);
+        MenuItem clearCookiesMenuItem = menu.findItem(R.id.clear_cookies);
+        MenuItem clearFormDataMenuItem = menu.findItem(R.id.clear_form_data);
+        MenuItem fontSizeMenuItem = menu.findItem(R.id.font_size);
+        MenuItem displayImagesMenuItem = menu.findItem(R.id.display_images);
         MenuItem refreshMenuItem = menu.findItem(R.id.refresh);
 
         // Set the status of the menu item checkboxes.
-        toggleFirstPartyCookies.setChecked(firstPartyCookiesEnabled);
-        toggleThirdPartyCookies.setChecked(thirdPartyCookiesEnabled);
-        toggleDomStorage.setChecked(domStorageEnabled);
-        toggleSaveFormData.setChecked(saveFormDataEnabled);
+        toggleFirstPartyCookiesMenuItem.setChecked(firstPartyCookiesEnabled);
+        toggleThirdPartyCookiesMenuItem.setChecked(thirdPartyCookiesEnabled);
+        toggleDomStorageMenuItem.setChecked(domStorageEnabled);
+        toggleSaveFormDataMenuItem.setChecked(saveFormDataEnabled);
+        displayImagesMenuItem.setChecked(mainWebView.getSettings().getLoadsImagesAutomatically());
 
         // Enable third-party cookies if first-party cookies are enabled.
-        toggleThirdPartyCookies.setEnabled(firstPartyCookiesEnabled);
+        toggleThirdPartyCookiesMenuItem.setEnabled(firstPartyCookiesEnabled);
 
         // Enable DOM Storage if JavaScript is enabled.
-        toggleDomStorage.setEnabled(javaScriptEnabled);
+        toggleDomStorageMenuItem.setEnabled(javaScriptEnabled);
 
         // Enable Clear Cookies if there are any.
-        clearCookies.setEnabled(cookieManager.hasCookies());
+        clearCookiesMenuItem.setEnabled(cookieManager.hasCookies());
 
         // Enable Clear Form Data is there is any.
         WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(this);
-        clearFormData.setEnabled(mainWebViewDatabase.hasFormData());
-
-        // Only show `Refresh` if `swipeToRefresh` is disabled.
-        refreshMenuItem.setVisible(!swipeToRefreshEnabled);
+        clearFormDataMenuItem.setEnabled(mainWebViewDatabase.hasFormData());
 
         // Initialize font size variables.
         int fontSize = mainWebView.getSettings().getTextZoom();
@@ -996,55 +1058,57 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         switch (fontSize) {
             case 25:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.twenty_five_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeTwentyFivePercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_twenty_five_percent);
                 break;
 
             case 50:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.fifty_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeFiftyPercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_fifty_percent);
                 break;
 
             case 75:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.seventy_five_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeSeventyFivePercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_seventy_five_percent);
                 break;
 
             case 100:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.one_hundred_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeOneHundredPercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_percent);
                 break;
 
             case 125:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.one_hundred_twenty_five_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeOneHundredTwentyFivePercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_twenty_five_percent);
                 break;
 
             case 150:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.one_hundred_fifty_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeOneHundredFiftyPercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_fifty_percent);
                 break;
 
             case 175:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.one_hundred_seventy_five_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeOneHundredSeventyFivePercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_seventy_five_percent);
                 break;
 
             case 200:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.two_hundred_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeTwoHundredPercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_two_hundred_percent);
                 break;
 
             default:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.one_hundred_percent);
-                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeOneHundredPercent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_percent);
                 break;
         }
 
         // Set the font size title and select the current size menu item.
-        MenuItem fontSizeMenuItem = menu.findItem(R.id.fontSize);
         fontSizeMenuItem.setTitle(fontSizeTitle);
         selectedFontSizeMenuItem.setChecked(true);
 
+        // Only show `Refresh` if `swipeToRefresh` is disabled.
+        refreshMenuItem.setVisible(!swipeToRefreshEnabled);
+
         // Run all the other default commands.
         super.onPrepareOptionsMenu(menu);
 
@@ -1062,7 +1126,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
 
         // Set the commands that relate to the menu entries.
         switch (menuItemId) {
-            case R.id.toggleJavaScript:
+            case R.id.toggle_javascript:
                 // Switch the status of javaScriptEnabled.
                 javaScriptEnabled = !javaScriptEnabled;
 
@@ -1085,7 +1149,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 mainWebView.reload();
                 return true;
 
-            case R.id.toggleFirstPartyCookies:
+            case R.id.toggle_first_party_cookies:
                 // Switch the status of firstPartyCookiesEnabled.
                 firstPartyCookiesEnabled = !firstPartyCookiesEnabled;
 
@@ -1111,7 +1175,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 mainWebView.reload();
                 return true;
 
-            case R.id.toggleThirdPartyCookies:
+            case R.id.toggle_third_party_cookies:
                 if (Build.VERSION.SDK_INT >= 21) {
                     // Switch the status of thirdPartyCookiesEnabled.
                     thirdPartyCookiesEnabled = !thirdPartyCookiesEnabled;
@@ -1134,7 +1198,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 } // Else do nothing because SDK < 21.
                 return true;
 
-            case R.id.toggleDomStorage:
+            case R.id.toggle_dom_storage:
                 // Switch the status of domStorageEnabled.
                 domStorageEnabled = !domStorageEnabled;
 
@@ -1158,7 +1222,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 mainWebView.reload();
                 return true;
 
-            case R.id.toggleSaveFormData:
+            case R.id.toggle_save_form_data:
                 // Switch the status of saveFormDataEnabled.
                 saveFormDataEnabled = !saveFormDataEnabled;
 
@@ -1182,7 +1246,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 mainWebView.reload();
                 return true;
 
-            case R.id.clearCookies:
+            case R.id.clear_cookies:
                 if (Build.VERSION.SDK_INT < 21) {
                     cookieManager.removeAllCookie();
                 } else {
@@ -1191,50 +1255,62 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 Snackbar.make(findViewById(R.id.main_webview), R.string.cookies_deleted, Snackbar.LENGTH_SHORT).show();
                 return true;
 
-            case R.id.clearDomStorage:
+            case R.id.clear_dom_storage:
                 WebStorage webStorage = WebStorage.getInstance();
                 webStorage.deleteAllData();
                 Snackbar.make(findViewById(R.id.main_webview), R.string.dom_storage_deleted, Snackbar.LENGTH_SHORT).show();
                 return true;
 
-            case R.id.clearFormData:
+            case R.id.clear_form_data:
                 WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(this);
                 mainWebViewDatabase.clearFormData();
                 Snackbar.make(findViewById(R.id.main_webview), R.string.form_data_deleted, Snackbar.LENGTH_SHORT).show();
                 return true;
 
-            case R.id.fontSizeTwentyFivePercent:
+            case R.id.font_size_twenty_five_percent:
                 mainWebView.getSettings().setTextZoom(25);
                 return true;
 
-            case R.id.fontSizeFiftyPercent:
+            case R.id.font_size_fifty_percent:
                 mainWebView.getSettings().setTextZoom(50);
                 return true;
 
-            case R.id.fontSizeSeventyFivePercent:
+            case R.id.font_size_seventy_five_percent:
                 mainWebView.getSettings().setTextZoom(75);
                 return true;
 
-            case R.id.fontSizeOneHundredPercent:
+            case R.id.font_size_one_hundred_percent:
                 mainWebView.getSettings().setTextZoom(100);
                 return true;
 
-            case R.id.fontSizeOneHundredTwentyFivePercent:
+            case R.id.font_size_one_hundred_twenty_five_percent:
                 mainWebView.getSettings().setTextZoom(125);
                 return true;
 
-            case R.id.fontSizeOneHundredFiftyPercent:
+            case R.id.font_size_one_hundred_fifty_percent:
                 mainWebView.getSettings().setTextZoom(150);
                 return true;
 
-            case R.id.fontSizeOneHundredSeventyFivePercent:
+            case R.id.font_size_one_hundred_seventy_five_percent:
                 mainWebView.getSettings().setTextZoom(175);
                 return true;
 
-            case R.id.fontSizeTwoHundredPercent:
+            case R.id.font_size_two_hundred_percent:
                 mainWebView.getSettings().setTextZoom(200);
                 return true;
 
+            case R.id.display_images:
+                if (mainWebView.getSettings().getLoadsImagesAutomatically()) {  // Images are currently loaded automatically.
+                    mainWebView.getSettings().setLoadsImagesAutomatically(false);
+                    mainWebView.reload();
+                } else {  // Images are not currently loaded automatically.
+                    mainWebView.getSettings().setLoadsImagesAutomatically(true);
+                }
+
+                // Set `onTheFlyDisplayImagesSet`.
+                onTheFlyDisplayImagesSet = true;
+                return true;
+
             case R.id.share:
                 // Setup the share string.
                 String shareString;
@@ -1288,7 +1364,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 printManager.print(getResources().getString(R.string.privacy_browser_web_page), printDocumentAdapter, null);
                 return true;
 
-            case R.id.addToHomescreen:
+            case R.id.add_to_homescreen:
                 // Show the `CreateHomeScreenShortcutDialog` `AlertDialog` and name this instance `R.string.create_shortcut`.
                 AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcutDialog();
                 createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.create_shortcut));
@@ -1832,50 +1908,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         }
     }
 
-    @Override
-    public void onPause() {
-        // Pause `mainWebView`.
-        mainWebView.onPause();
-
-        // Stop all JavaScript.
-        mainWebView.pauseTimers();
-
-        // Pause the adView or it will continue to consume resources in the background on the free flavor.
-        if (BuildConfig.FLAVOR.contentEquals("free")) {
-            BannerAd.pauseAd(adView);
-        }
-
-        super.onPause();
-    }
-
-    @Override
-    public void onResume() {  // `onResume()` also runs every time the app starts after `onCreate()` and `onStart()`.
-        super.onResume();
-
-        // Resume JavaScript (if enabled).
-        mainWebView.resumeTimers();
-
-        // Resume `mainWebView`.
-        mainWebView.onResume();
-
-        // Resume the adView for the free flavor.
-        if (BuildConfig.FLAVOR.contentEquals("free")) {
-            BannerAd.resumeAd(adView);
-        }
-    }
-
-    @Override
-    public void onRestart() {
-        super.onRestart();
-
-        // Apply the settings from shared preferences, which might have been changed in `SettingsActivity`.
-        applyAppSettings();
-
-        // Update the privacy icon.  `true` runs `invalidateOptionsMenu` as the last step.
-        updatePrivacyIcons(true);
-
-    }
-
     private void loadUrlFromTextBox() throws UnsupportedEncodingException {
         // Get the text from urlTextBox and convert it to a string.  trim() removes white spaces from the beginning and end of the string.
         String unformattedUrlString = urlTextBox.getText().toString().trim();
@@ -1933,6 +1965,176 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         mainWebView.loadUrl(url, customHeaders);
     }
 
+    public void findPreviousOnPage(View view) {
+        // Go to the previous highlighted phrase on the page.  `false` goes backwards instead of forwards.
+        mainWebView.findNext(false);
+    }
+
+    public void findNextOnPage(View view) {
+        // Go to the next highlighted phrase on the page. `true` goes forwards instead of backwards.
+        mainWebView.findNext(true);
+    }
+
+    public void closeFindOnPage(View view) {
+        // Delete the contents of `find_on_page_edittext`.
+        findOnPageEditText.setText(null);
+
+        // Clear the highlighted phrases.
+        mainWebView.clearMatches();
+
+        // Hide the Find on Page `RelativeLayout`.
+        findOnPageLinearLayout.setVisibility(View.GONE);
+
+        // Show the URL app bar.
+        supportAppBar.setVisibility(View.VISIBLE);
+
+        // Hide the keyboard so we can see the webpage.  `0` indicates no additional flags.
+        inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0);
+    }
+
+    private void applyAppSettings() {
+        // Get the shared preference values.  `this` references the current context.
+        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+        // Store the values from `sharedPreferences` in variables.
+        String homepageString = sharedPreferences.getString("homepage", "https://duckduckgo.com");
+        String torHomepageString = sharedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion");
+        String torSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
+        String torSearchCustomURLString = sharedPreferences.getString("tor_search_custom_url", "");
+        String searchString = sharedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
+        String searchCustomURLString = sharedPreferences.getString("search_custom_url", "");
+        adBlockerEnabled = sharedPreferences.getBoolean("block_ads", true);
+        incognitoModeEnabled = sharedPreferences.getBoolean("incognito_mode", false);
+        boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", false);
+        boolean proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
+        fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
+        hideSystemBarsOnFullscreen = sharedPreferences.getBoolean("hide_system_bars", false);
+        translucentNavigationBarOnFullscreen = sharedPreferences.getBoolean("translucent_navigation_bar", true);
+        swipeToRefreshEnabled = sharedPreferences.getBoolean("swipe_to_refresh", false);
+        displayWebpageImagesBoolean = sharedPreferences.getBoolean("display_webpage_images", true);
+
+        // Set the homepage, search, and proxy options.
+        if (proxyThroughOrbot) {  // Set the Tor options.
+            // Set `torHomepageString` as `homepage`.
+            homepage = torHomepageString;
+
+            // If formattedUrlString is null assign the homepage to it.
+            if (formattedUrlString == null) {
+                formattedUrlString = homepage;
+            }
+
+            // Set the search URL.
+            if (torSearchString.equals("Custom URL")) {  // Get the custom URL string.
+                searchURL = torSearchCustomURLString;
+            } else {  // Use the string from the pre-built list.
+                searchURL = torSearchString;
+            }
+
+            // Set the proxy.  `this` refers to the current activity where an `AlertDialog` might be displayed.
+            OrbotProxyHelper.setProxy(getApplicationContext(), this, "localhost", "8118");
+
+            // Display a message to the user if we are waiting on Orbot.
+            if (!orbotStatus.equals("ON")) {
+                // Set `waitingForOrbot`.
+                waitingForOrbot = true;
+
+                // Load a waiting page.  `null` specifies no encoding, which defaults to ASCII.
+                mainWebView.loadData(waitingForOrbotHTMLString, "text/html", null);
+            }
+        } else {  // Set the non-Tor options.
+            // Set `homepageString` as `homepage`.
+            homepage = homepageString;
+
+            // If formattedUrlString is null assign the homepage to it.
+            if (formattedUrlString == null) {
+                formattedUrlString = homepage;
+            }
+
+            // Set the search URL.
+            if (searchString.equals("Custom URL")) {  // Get the custom URL string.
+                searchURL = searchCustomURLString;
+            } else {  // Use the string from the pre-built list.
+                searchURL = searchString;
+            }
+
+            // Reset the proxy to default.  The host is `""` and the port is `"0"`.
+            OrbotProxyHelper.setProxy(getApplicationContext(), this, "", "0");
+
+            // Reset `waitingForOrbot.
+            waitingForOrbot = false;
+        }
+
+        // Set swipe to refresh.
+        swipeRefreshLayout.setEnabled(swipeToRefreshEnabled);
+
+        // Set Do Not Track status.
+        if (doNotTrackEnabled) {
+            customHeaders.put("DNT", "1");
+        } else {
+            customHeaders.remove("DNT");
+        }
+
+        // Apply the appropriate full screen mode the `SYSTEM_UI` flags.
+        if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) {
+            if (hideSystemBarsOnFullscreen) {  // Hide everything.
+                // Remove the translucent navigation setting if it is currently flagged.
+                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+
+                // Remove the translucent status bar overlay.
+                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+                // 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.
+                 */
+                rootCoordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+            } else {  // Hide everything except the status and navigation bars.
+                // Add the translucent status flag if it is unset.
+                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+                if (translucentNavigationBarOnFullscreen) {
+                    // Set the navigation bar to be translucent.
+                    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+                } else {
+                    // Set the navigation bar to be black.
+                    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+                }
+            }
+        } else {  // Switch to normal viewing mode.
+            // Reset `inFullScreenBrowsingMode` to `false`.
+            inFullScreenBrowsingMode = false;
+
+            // Show the `appBar` if `findOnPageLinearLayout` is not visible.
+            if (findOnPageLinearLayout.getVisibility() == View.GONE) {
+                appBar.show();
+            }
+
+            // Show the `BannerAd` in the free flavor.
+            if (BuildConfig.FLAVOR.contentEquals("free")) {
+                // Reload the ad.  Because the screen may have rotated, we need to use `reloadAfterRotate`.
+                BannerAd.reloadAfterRotate(adView, getApplicationContext(), getString(R.string.ad_id));
+
+                // Reinitialize the `adView` variable, as the `View` will have been removed and re-added by `BannerAd.reloadAfterRotate()`.
+                adView = findViewById(R.id.adview);
+            }
+
+            // Remove the translucent navigation bar flag if it is set.
+            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+
+            // Add the translucent status flag if it is unset.  This also resets `drawerLayout's` `View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`.
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+            // Remove any `SYSTEM_UI` flags from `rootCoordinatorLayout`.
+            rootCoordinatorLayout.setSystemUiVisibility(0);
+
+            // Constrain `rootCoordinatorLayout` inside the status and navigation bars.
+            rootCoordinatorLayout.setFitsSystemWindows(true);
+        }
+    }
+
     // We have to use the deprecated `.getDrawable()` until the minimum API >= 21.
     @SuppressWarnings("deprecation")
     private void applyDomainSettings(String url) {
@@ -1991,21 +2193,21 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
             // Close `domainNameCursor.
             domainNameCursor.close();
 
-            // Initialize variables to track if this domain has stored domain settings, and if so, under which name.
-            boolean hostHasDomainSettings = false;
+            // Initialize variables to track if domain settings will be applied and, if so, under which name.
+            domainSettingsApplied = false;
             String domainNameInDatabase = null;
 
             // Check the hostname.
             if (domainSettingsSet.contains(hostName)) {
-                hostHasDomainSettings = true;
+                domainSettingsApplied = true;
                 domainNameInDatabase = hostName;
             }
 
             // If `hostName` is not `null`, check all the subdomains of `hostName` against wildcard domains in `domainCursor`.
             if (hostName != null) {
-                while (hostName.contains(".") && !hostHasDomainSettings) {  // Stop checking if we run out of  `.` or if we already know that `hostHasDomainSettings` is `true`.
+                while (hostName.contains(".") && !domainSettingsApplied) {  // Stop checking if we run out of  `.` or if we already know that `domainSettingsApplied` is `true`.
                     if (domainSettingsSet.contains("*." + hostName)) {  // Check the host name prepended by `*.`.
-                        hostHasDomainSettings = true;
+                        domainSettingsApplied = true;
                         domainNameInDatabase = "*." + hostName;
                     }
 
@@ -2014,7 +2216,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 }
             }
 
-            if (hostHasDomainSettings) {  // The url we are loading has custom domain settings.
+            // Get a handle for the shared preference.  `this` references the current context.
+            SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+            if (domainSettingsApplied) {  // The url we are loading has custom domain settings.
                 // Get a cursor for the current host and move it to the first position.
                 Cursor currentHostDomainSettingsCursor = domainsDatabaseHelper.getCursorForDomainName(domainNameInDatabase);
                 currentHostDomainSettingsCursor.moveToFirst();
@@ -2025,8 +2230,9 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 thirdPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1);
                 domStorageEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1);
                 saveFormDataEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1);
-                String userAgentString = (currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT)));
-                int fontSize = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE)));
+                String userAgentString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
+                int fontSize = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
+                displayWebpageImagesInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
 
                 // Close `currentHostDomainSettingsCursor`.
                 currentHostDomainSettingsCursor.close();
@@ -2055,9 +2261,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 // Set a green background on `urlTextBox` to indicate that custom domain settings are being used.  We have to use the deprecated `.getDrawable()` until the minimum API >= 21.
                 urlAppBarRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_green));
             } else {  // The URL we are loading does not have custom domain settings.  Load the defaults.
-                // Get the shared preference values.  `this` references the current context.
-                SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-
                 // Store the values from `sharedPreferences` in variables.
                 javaScriptEnabled = sharedPreferences.getBoolean("javascript_enabled", false);
                 firstPartyCookiesEnabled = sharedPreferences.getBoolean("first_party_cookies_enabled", false);
@@ -2105,6 +2308,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
             // Close `domainsDatabaseHelper`.
             domainsDatabaseHelper.close();
 
+            // Remove the `onTheFlyDisplayImagesSet` flag and set the display webpage images mode.  `true` indicates that custom domain settings are applied.
+            onTheFlyDisplayImagesSet = false;
+            setDisplayWebpageImages();
+
             // Update the privacy icons, but only if `mainMenu` has already been populated.
             if (mainMenu != null) {
                 updatePrivacyIcons(true);
@@ -2112,212 +2319,65 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         }
     }
 
-    public void findPreviousOnPage(View view) {
-        // Go to the previous highlighted phrase on the page.  `false` goes backwards instead of forwards.
-        mainWebView.findNext(false);
-    }
-
-    public void findNextOnPage(View view) {
-        // Go to the next highlighted phrase on the page. `true` goes forwards instead of backwards.
-        mainWebView.findNext(true);
-    }
-
-    public void closeFindOnPage(View view) {
-        // Delete the contents of `find_on_page_edittext`.
-        findOnPageEditText.setText(null);
-
-        // Clear the highlighted phrases.
-        mainWebView.clearMatches();
-
-        // Hide the Find on Page `RelativeLayout`.
-        findOnPageLinearLayout.setVisibility(View.GONE);
-
-        // Show the URL app bar.
-        supportAppBar.setVisibility(View.VISIBLE);
-
-        // Hide the keyboard so we can see the webpage.  `0` indicates no additional flags.
-        inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0);
-    }
-
-    private void applyAppSettings() {
-        // Get the shared preference values.  `this` references the current context.
-        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-
-        // Store the values from `sharedPreferences` in variables.
-        String homepageString = sharedPreferences.getString("homepage", "https://duckduckgo.com");
-        String torHomepageString = sharedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion");
-        String torSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
-        String torSearchCustomURLString = sharedPreferences.getString("tor_search_custom_url", "");
-        String searchString = sharedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
-        String searchCustomURLString = sharedPreferences.getString("search_custom_url", "");
-        adBlockerEnabled = sharedPreferences.getBoolean("block_ads", true);
-        incognitoModeEnabled = sharedPreferences.getBoolean("incognito_mode", false);
-        boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", false);
-        boolean proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
-        fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
-        hideSystemBarsOnFullscreen = sharedPreferences.getBoolean("hide_system_bars", false);
-        translucentNavigationBarOnFullscreen = sharedPreferences.getBoolean("translucent_navigation_bar", true);
-        swipeToRefreshEnabled = sharedPreferences.getBoolean("swipe_to_refresh", false);
-
-        // Set the homepage, search, and proxy options.
-        if (proxyThroughOrbot) {  // Set the Tor options.
-            // Set `torHomepageString` as `homepage`.
-            homepage = torHomepageString;
-
-            // If formattedUrlString is null assign the homepage to it.
-            if (formattedUrlString == null) {
-                formattedUrlString = homepage;
-            }
-
-            // Set the search URL.
-            if (torSearchString.equals("Custom URL")) {  // Get the custom URL string.
-                searchURL = torSearchCustomURLString;
-            } else {  // Use the string from the pre-built list.
-                searchURL = torSearchString;
-            }
-
-            // Set the proxy.  `this` refers to the current activity where an `AlertDialog` might be displayed.
-            OrbotProxyHelper.setProxy(getApplicationContext(), this, "localhost", "8118");
-
-            // Display a message to the user if we are waiting on Orbot.
-            if (!orbotStatus.equals("ON")) {
-                // Set `waitingForOrbot`.
-                waitingForOrbot = true;
-
-                // Load a waiting page.  `null` specifies no encoding, which defaults to ASCII.
-                mainWebView.loadData(waitingForOrbotHTMLString, "text/html", null);
-            }
-        } else {  // Set the non-Tor options.
-            // Set `homepageString` as `homepage`.
-            homepage = homepageString;
-
-            // If formattedUrlString is null assign the homepage to it.
-            if (formattedUrlString == null) {
-                formattedUrlString = homepage;
-            }
-
-            // Set the search URL.
-            if (searchString.equals("Custom URL")) {  // Get the custom URL string.
-                searchURL = searchCustomURLString;
-            } else {  // Use the string from the pre-built list.
-                searchURL = searchString;
-            }
-
-            // Reset the proxy to default.  The host is `""` and the port is `"0"`.
-            OrbotProxyHelper.setProxy(getApplicationContext(), this, "", "0");
-
-            // Reset `waitingForOrbot.
-            waitingForOrbot = false;
-        }
-
-        // Set swipe to refresh.
-        swipeRefreshLayout.setEnabled(swipeToRefreshEnabled);
-
-        // Set Do Not Track status.
-        if (doNotTrackEnabled) {
-            customHeaders.put("DNT", "1");
-        } else {
-            customHeaders.remove("DNT");
-        }
-
-        // Apply the appropriate full screen mode the `SYSTEM_UI` flags.
-        if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) {
-            if (hideSystemBarsOnFullscreen) {  // Hide everything.
-                // Remove the translucent navigation setting if it is currently flagged.
-                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
-
-                // Remove the translucent status bar overlay.
-                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-
-                // 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);
+    private void setDisplayWebpageImages() {
+        if (!onTheFlyDisplayImagesSet) {
+            if (domainSettingsApplied) {  // Custom domain settings are applied.
+                switch (displayWebpageImagesInt) {
+                    case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
+                        mainWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImagesBoolean);
+                        break;
 
-                /* 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);
-            } else {  // Hide everything except the status and navigation bars.
-                // Add the translucent status flag if it is unset.
-                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                    case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
+                        mainWebView.getSettings().setLoadsImagesAutomatically(true);
+                        break;
 
-                if (translucentNavigationBarOnFullscreen) {
-                    // Set the navigation bar to be translucent.
-                    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
-                } else {
-                    // Set the navigation bar to be black.
-                    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+                    case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
+                        mainWebView.getSettings().setLoadsImagesAutomatically(false);
+                        break;
                 }
+            } else {  // Default settings are applied.
+                mainWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImagesBoolean);
             }
-        } else {  // Switch to normal viewing mode.
-            // Reset `inFullScreenBrowsingMode` to `false`.
-            inFullScreenBrowsingMode = false;
-
-            // Show the `appBar` if `findOnPageLinearLayout` is not visible.
-            if (findOnPageLinearLayout.getVisibility() == View.GONE) {
-                appBar.show();
-            }
-
-            // Show the `BannerAd` in the free flavor.
-            if (BuildConfig.FLAVOR.contentEquals("free")) {
-                // Reload the ad.  Because the screen may have rotated, we need to use `reloadAfterRotate`.
-                BannerAd.reloadAfterRotate(adView, getApplicationContext(), getString(R.string.ad_id));
-
-                // Reinitialize the `adView` variable, as the `View` will have been removed and re-added by `BannerAd.reloadAfterRotate()`.
-                adView = findViewById(R.id.adview);
-            }
-
-            // Remove the translucent navigation bar flag if it is set.
-            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
-
-            // Add the translucent status flag if it is unset.  This also resets `drawerLayout's` `View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`.
-            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-
-            // Remove any `SYSTEM_UI` flags from `rootCoordinatorLayout`.
-            rootCoordinatorLayout.setSystemUiVisibility(0);
-
-            // Constrain `rootCoordinatorLayout` inside the status and navigation bars.
-            rootCoordinatorLayout.setFitsSystemWindows(true);
         }
     }
 
     private void updatePrivacyIcons(boolean runInvalidateOptionsMenu) {
         // Get handles for the icons.
-        MenuItem privacyIcon = mainMenu.findItem(R.id.toggleJavaScript);
-        MenuItem firstPartyCookiesIcon = mainMenu.findItem(R.id.toggleFirstPartyCookies);
-        MenuItem domStorageIcon = mainMenu.findItem(R.id.toggleDomStorage);
-        MenuItem formDataIcon = mainMenu.findItem(R.id.toggleSaveFormData);
+        MenuItem privacyIconMenuItem = mainMenu.findItem(R.id.toggle_javascript);
+        MenuItem firstPartyCookiesIconMenuItem = mainMenu.findItem(R.id.toggle_first_party_cookies);
+        MenuItem domStorageIconMenuItem = mainMenu.findItem(R.id.toggle_dom_storage);
+        MenuItem formDataIconMenuItem = mainMenu.findItem(R.id.toggle_save_form_data);
 
         // Update `privacyIcon`.
         if (javaScriptEnabled) {  // JavaScript is enabled.
-            privacyIcon.setIcon(R.drawable.javascript_enabled);
+            privacyIconMenuItem.setIcon(R.drawable.javascript_enabled);
         } else if (firstPartyCookiesEnabled) {  // JavaScript is disabled but cookies are enabled.
-            privacyIcon.setIcon(R.drawable.warning);
+            privacyIconMenuItem.setIcon(R.drawable.warning);
         } else {  // All the dangerous features are disabled.
-            privacyIcon.setIcon(R.drawable.privacy_mode);
+            privacyIconMenuItem.setIcon(R.drawable.privacy_mode);
         }
 
         // Update `firstPartyCookiesIcon`.
         if (firstPartyCookiesEnabled) {  // First-party cookies are enabled.
-            firstPartyCookiesIcon.setIcon(R.drawable.cookies_enabled);
+            firstPartyCookiesIconMenuItem.setIcon(R.drawable.cookies_enabled);
         } else {  // First-party cookies are disabled.
-            firstPartyCookiesIcon.setIcon(R.drawable.cookies_disabled);
+            firstPartyCookiesIconMenuItem.setIcon(R.drawable.cookies_disabled);
         }
 
         // Update `domStorageIcon`.
         if (javaScriptEnabled && domStorageEnabled) {  // Both JavaScript and DOM storage are enabled.
-            domStorageIcon.setIcon(R.drawable.dom_storage_enabled);
+            domStorageIconMenuItem.setIcon(R.drawable.dom_storage_enabled);
         } else if (javaScriptEnabled) {  // JavaScript is enabled but DOM storage is disabled.
-            domStorageIcon.setIcon(R.drawable.dom_storage_disabled);
+            domStorageIconMenuItem.setIcon(R.drawable.dom_storage_disabled);
         } else {  // JavaScript is disabled, so DOM storage is ghosted.
-            domStorageIcon.setIcon(R.drawable.dom_storage_ghosted);
+            domStorageIconMenuItem.setIcon(R.drawable.dom_storage_ghosted);
         }
 
         // Update `formDataIcon`.
         if (saveFormDataEnabled) {  // Form data is enabled.
-            formDataIcon.setIcon(R.drawable.form_data_enabled);
+            formDataIconMenuItem.setIcon(R.drawable.form_data_enabled);
         } else {  // Form data is disabled.
-            formDataIcon.setIcon(R.drawable.form_data_disabled);
+            formDataIconMenuItem.setIcon(R.drawable.form_data_disabled);
         }
 
         // `invalidateOptionsMenu` calls `onPrepareOptionsMenu()` and redraws the icons in the `AppBar`.  `this` references the current activity.
index 9c82f070c123bdd6735b393def2c953e620c7c2b..075d5ece52f91a6df5699f2eec17ed11125ae733 100644 (file)
@@ -21,12 +21,12 @@ package com.stoutner.privacybrowser.activities;
 
 import android.os.Bundle;
 import android.preference.PreferenceFragment;
+import android.support.v4.app.NavUtils;
 import android.support.v7.app.AppCompatActivity;
 
 import com.stoutner.privacybrowser.fragments.SettingsFragment;
 
 public class SettingsActivity extends AppCompatActivity {
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
index bdd0302dca7d5f14c22ffc024afe7882b42ad63b..4416d3019da0a3ccc3b6d863ab5fddfd5581e863 100644 (file)
@@ -41,6 +41,7 @@ import android.widget.Switch;
 import android.widget.TextView;
 
 import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.activities.MainWebViewActivity;
 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
 
 public class DomainSettingsFragment extends Fragment {
@@ -85,6 +86,8 @@ public class DomainSettingsFragment extends Fragment {
         final TextView userAgentTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
         final EditText customUserAgentEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
         Spinner fontSizeSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
+        final ImageView displayWebpageImagesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
+        Spinner displayWebpageImagesSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
 
         // Initialize the database handler.  `this` specifies the context.  The two `nulls` do not specify the database name or a `CursorFactory`.
         // The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
@@ -103,20 +106,24 @@ public class DomainSettingsFragment extends Fragment {
         int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA));
         final String currentUserAgentString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
         int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
+        int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
 
         // Create `ArrayAdapters` for the `Spinners`and their `entry values`.
         ArrayAdapter<CharSequence> userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.user_agent_entries, android.R.layout.simple_spinner_item);
         final ArrayAdapter<CharSequence> userAgentEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.user_agent_entry_values, android.R.layout.simple_spinner_item);
         ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.default_font_size_entries, android.R.layout.simple_spinner_item);
         ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.default_font_size_entry_values, android.R.layout.simple_spinner_item);
+        final ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_website_images_array, android.R.layout.simple_spinner_item);
 
         // Set the drop down style for the `ArrayAdapters`.
         userAgentArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         fontSizeArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        displayImagesArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
 
         // Set the `ArrayAdapters` for the `Spinners`.
         userAgentSpinner.setAdapter(userAgentArrayAdapter);
         fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
+        displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
 
         // Set the domain name from the the database cursor.
         domainNameEditText.setText(domainNameString);
@@ -179,16 +186,16 @@ public class DomainSettingsFragment extends Fragment {
                 domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_disabled));
             }
         } else {  // JavaScript is disabled.
-            // Set the status of DOM storage, but disable it.
+            // Set the checked status of DOM storage.
             if (domStorageEnabledInt == 1) {  // DOM storage is enabled but JavaScript is disabled.
                 domStorageEnabledSwitch.setChecked(true);
-                domStorageEnabledSwitch.setEnabled(false);
-                domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_ghosted));
             } else {  // Both JavaScript and DOM storage are disabled.
                 domStorageEnabledSwitch.setChecked(false);
-                domStorageEnabledSwitch.setEnabled(false);
-                domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_ghosted));
             }
+
+            // Disable `domStorageEnabledSwitch` and set the icon to be ghosted.
+            domStorageEnabledSwitch.setEnabled(false);
+            domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_ghosted));
         }
 
         // Set the form data status.  Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
@@ -246,6 +253,29 @@ public class DomainSettingsFragment extends Fragment {
         int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
         fontSizeSpinner.setSelection(fontSizeArrayPosition);
 
+        // Set the selected display website images mode.
+        displayWebpageImagesSpinner.setSelection(displayImagesInt);
+
+        // Set the display website images icon.
+        switch (displayImagesInt) {
+            case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
+                if (MainWebViewActivity.displayWebpageImagesBoolean) {
+                    displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled));
+                } else {
+                    displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled));
+                }
+                break;
+
+            case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
+                displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled));
+                break;
+
+            case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
+                displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled));
+                break;
+        }
+
+
         // Set the `javaScriptEnabledSwitch` `OnCheckedChangeListener()`.
         javaScriptEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
             @Override
@@ -389,6 +419,36 @@ public class DomainSettingsFragment extends Fragment {
             }
         });
 
+        // Set the `displayImagesSwitch` `onItemClickListener()`.
+        displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                // Update the icon.
+                switch (position) {
+                    case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
+                        if (MainWebViewActivity.displayWebpageImagesBoolean) {
+                            displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled));
+                        } else {
+                            displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled));
+                        }
+                        break;
+
+                    case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
+                        displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled));
+                        break;
+
+                    case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
+                        displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled));
+                        break;
+                }
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+                // Do nothing.
+            }
+        });
+
         return domainSettingsView;
     }
 }
index dcc548939e58c356020cf3a0baba24b67161950a..2ca684613699fcc570273af45773c09c2fca5014 100644 (file)
@@ -67,6 +67,7 @@ public class SettingsFragment extends PreferenceFragment {
         final Preference defaultFontSizePreference = findPreference("default_font_size");
         final Preference swipeToRefreshPreference = findPreference("swipe_to_refresh");
         final Preference displayAdditionalAppBarIconsPreference = findPreference("display_additional_app_bar_icons");
+        final Preference displayWebpageImagesPreference = findPreference("display_webpage_images");
 
         // Set dependencies.
         domStoragePreference.setDependency("javascript_enabled");
@@ -288,7 +289,7 @@ public class SettingsFragment extends PreferenceFragment {
                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
                 }
             }
-        } else {  // `fullScreenBrwosingModeBoolean` is false.
+        } else {  // `fullScreenBrowsingModeBoolean` is false.
             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_ghosted);
             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
@@ -308,6 +309,14 @@ public class SettingsFragment extends PreferenceFragment {
             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
         }
 
+        // Set the `displayWebpageImagesPreference` icon.
+        if (savedPreferences.getBoolean("display_webpage_images", true)) {
+            displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
+        } else {
+            displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
+        }
+
+
         // Listen for preference changes.
         preferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
             @Override
@@ -639,6 +648,15 @@ public class SettingsFragment extends PreferenceFragment {
                         }
                         break;
 
+                    case "display_webpage_images":
+                        // Update the icon.
+                        if (sharedPreferences.getBoolean("display_webpage_images", true)) {
+                            displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
+                        } else {
+                            displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
+                        }
+                        break;
+
                     default:
                         // If no match, do nothing.
                         break;
index 0e1448b4bd53a234c2762580b663c6ca9a714c71..f6bd47ad152c09b984ccba27dad37be76feda9ad 100644 (file)
@@ -26,7 +26,7 @@ import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 
 public class DomainsDatabaseHelper extends SQLiteOpenHelper {
-    private static final int SCHEMA_VERSION = 1;
+    private static final int SCHEMA_VERSION = 2;
     private static final String DOMAINS_DATABASE = "domains.db";
     private static final String DOMAINS_TABLE = "domains";
 
@@ -39,6 +39,11 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper {
     public static final String ENABLE_FORM_DATA = "enableformdata";
     public static final String USER_AGENT = "useragent";
     public static final String FONT_SIZE = "fontsize";
+    public static final String DISPLAY_IMAGES = "displayimages";
+
+    public static final int DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT = 0;
+    public static final int DISPLAY_WEBPAGE_IMAGES_ENABLED = 1;
+    public static final int DISPLAY_WEBPAGE_IMAGES_DISABLED = 2;
 
     // Initialize the database.  The lint warnings for the unused parameters are suppressed.
     public DomainsDatabaseHelper(Context context, @SuppressWarnings("UnusedParameters") String name, SQLiteDatabase.CursorFactory cursorFactory, @SuppressWarnings("UnusedParameters") int version) {
@@ -49,15 +54,16 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper {
     public void onCreate(SQLiteDatabase domainsDatabase) {
         // Setup the SQL string to create the `domains` table.
         final String CREATE_DOMAINS_TABLE = "CREATE TABLE " + DOMAINS_TABLE + " (" +
-                _ID + " integer primary key, " +
-                DOMAIN_NAME + " text, " +
-                ENABLE_JAVASCRIPT + " boolean, " +
-                ENABLE_FIRST_PARTY_COOKIES + " boolean, " +
-                ENABLE_THIRD_PARTY_COOKIES + " boolean, " +
-                ENABLE_DOM_STORAGE + " boolean, " +
-                ENABLE_FORM_DATA + " boolean, " +
-                USER_AGENT + " text, " +
-                FONT_SIZE + " integer);";
+                _ID + " INTEGER PRIMARY KEY, " +
+                DOMAIN_NAME + " TEXT, " +
+                ENABLE_JAVASCRIPT + " BOOLEAN, " +
+                ENABLE_FIRST_PARTY_COOKIES + " BOOLEAN, " +
+                ENABLE_THIRD_PARTY_COOKIES + " BOOLEAN, " +
+                ENABLE_DOM_STORAGE + " BOOLEAN, " +
+                ENABLE_FORM_DATA + " BOOLEAN, " +
+                USER_AGENT + " TEXT, " +
+                FONT_SIZE + " INTEGER, " +
+                DISPLAY_IMAGES + " INTEGER);";
 
         // Create the `domains` table if it doesn't exist.
         domainsDatabase.execSQL(CREATE_DOMAINS_TABLE);
@@ -65,7 +71,13 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper {
 
     @Override
     public void onUpgrade(SQLiteDatabase domainsDatabase, int oldVersion, int newVersion) {
-        // Code for upgrading the database will be added here when the schema version > 1.
+        // Upgrade `DOMAINS_TABLE`.
+        switch (oldVersion) {
+            // Upgrade from `SCHEMA_VERSION` 1.
+            case 1:
+                // Add the `DISPLAY_IMAGES` column.
+                domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + DISPLAY_IMAGES + " INTEGER");
+        }
     }
 
     public Cursor getDomainNameCursorOrderedByDomain() {
@@ -132,6 +144,7 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper {
         domainContentValues.put(ENABLE_FORM_DATA, false);
         domainContentValues.put(USER_AGENT, "PrivacyBrowser/1.0");
         domainContentValues.put(FONT_SIZE, "100");
+        domainContentValues.put(DISPLAY_IMAGES, 0);
 
         // Get a writable database handle.
         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
@@ -143,7 +156,8 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper {
         domainsDatabase.close();
     }
 
-    public void saveDomain(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize) {
+    public void saveDomain(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
+                           int displayImages) {
         // Store the domain data in a `ContentValues`.
         ContentValues domainContentValues = new ContentValues();
 
@@ -156,6 +170,7 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper {
         domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled);
         domainContentValues.put(USER_AGENT, userAgent);
         domainContentValues.put(FONT_SIZE, fontSize);
+        domainContentValues.put(DISPLAY_IMAGES, displayImages);
 
         // Get a writable database handle.
         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
diff --git a/app/src/main/res/drawable/images_disabled.xml b/app/src/main/res/drawable/images_disabled.xml
new file mode 100644 (file)
index 0000000..bd8526c
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- `images_disabled.xml` comes from the Android Material icon set, where it is called `ic_image`.  It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:autoMirrored="true"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    tools:ignore="VectorRaster" >
+
+    <!-- We have to use a hard coded color code until API >= 21.  Then we can use `@color`. -->
+    <path
+        android:fillColor="#88000000"
+        android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/images_enabled.xml b/app/src/main/res/drawable/images_enabled.xml
new file mode 100644 (file)
index 0000000..ee3387b
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- `images_enabled.xml` comes from the Android Material icon set, where it is called `ic_image`.  It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:autoMirrored="true"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    tools:ignore="VectorRaster" >
+
+    <!-- We have to use a hard coded color code until API >= 21.  Then we can use `@color`. -->
+    <path
+        android:fillColor="#FF1565C0"
+        android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
+</vector>
index 6878c15f51028924ffbdebd459ccfea0cfb82b19..cdda48e8af5fc4d12f122f9464685cb42c590c41 100644 (file)
@@ -40,7 +40,7 @@
         <LinearLayout
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
-            android:orientation="vertical">
+            android:orientation="vertical" >
 
             <LinearLayout
                 android:layout_height="wrap_content"
@@ -94,7 +94,6 @@
                 android:layout_width="wrap_content"
                 android:layout_marginEnd="10dp"
                 android:layout_gravity="center_vertical"
-                android:src="@drawable/privacy_mode"
                 tools:ignore="contentDescription" />
 
             <Switch
                 android:layout_marginTop="1dp"
                 android:layout_marginEnd="10dp"
                 android:layout_gravity="center_vertical"
-                android:src="@drawable/cookies_disabled"
                 tools:ignore="contentDescription" />
 
             <Switch
                 android:layout_marginTop="1dp"
                 android:layout_marginEnd="10dp"
                 android:layout_gravity="center_vertical"
-                android:src="@drawable/cookies_disabled"
                 tools:ignore="contentDescription" />
 
             <Switch
                 android:layout_marginTop="1dp"
                 android:layout_marginEnd="10dp"
                 android:layout_gravity="center_vertical"
-                android:src="@drawable/dom_storage_disabled"
                 tools:ignore="contentDescription" />
 
             <Switch
         <LinearLayout
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
-            android:orientation="horizontal">
+            android:orientation="horizontal" >
 
             <ImageView
                 android:id="@+id/domain_settings_form_data_imageview"
                 android:layout_marginTop="1dp"
                 android:layout_marginEnd="10dp"
                 android:layout_gravity="center_vertical"
-                android:src="@drawable/form_data_disabled"
                 tools:ignore="contentDescription" />
 
             <Switch
             <LinearLayout
                 android:layout_height="wrap_content"
                 android:layout_width="match_parent"
-                android:orientation="horizontal">
+                android:orientation="horizontal" >
 
                 <ImageView
                     android:layout_height="wrap_content"
                     android:id="@+id/domain_settings_user_agent_spinner"
                     android:layout_height="wrap_content"
                     android:layout_width="match_parent"
-                    android:labelFor="@+id/domain_settings_custom_user_agent_edittext"/>
+                    android:labelFor="@+id/domain_settings_custom_user_agent_edittext" />
             </LinearLayout>
 
             <TextView
                 android:layout_width="match_parent"
                 android:layout_marginStart="43dp"
                 android:layout_marginEnd="36dp"
-                android:textSize="13sp"/>
+                android:textSize="13sp" />
 
             <EditText
                 android:id="@id/domain_settings_custom_user_agent_edittext"
                 android:layout_height="wrap_content"
                 android:layout_width="match_parent"
                 android:layout_marginTop="14dp"
-                android:layout_marginBottom="14dp"/>
+                android:layout_marginBottom="14dp" />
+        </LinearLayout>
+
+        <!-- Display Images. -->
+        <LinearLayout
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:orientation="horizontal" >
+
+            <ImageView
+                android:id="@+id/domain_settings_display_webpage_images_imageview"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:layout_marginTop="1dp"
+                android:layout_marginEnd="10dp"
+                android:layout_gravity="center_vertical"
+                android:contentDescription="@string/display_webpage_images" />
+
+            <Spinner
+                android:id="@+id/domain_settings_display_webpage_images_spinner"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:layout_marginTop="14dp"
+                android:layout_marginBottom="14dp" />
         </LinearLayout>
     </LinearLayout>
 </ScrollView>
\ No newline at end of file
index d2d5743201942a6403698630b2a40a2663e3258a..df62da64ddb4361d5d110c177adbc03fad5fe9fd 100644 (file)
     tools:context=".activities.MainWebViewActivity">
 
     <item
-        android:id="@+id/toggleJavaScript"
+        android:id="@+id/toggle_javascript"
         android:title="@string/javascript"
         android:orderInCategory="10"
         app:showAsAction="ifRoom" />
 
     <item
-        android:id="@+id/toggleFirstPartyCookies"
+        android:id="@+id/toggle_first_party_cookies"
         android:title="@string/first_party_cookies"
         android:orderInCategory="20"
         android:checkable="true"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/toggleThirdPartyCookies"
+        android:id="@+id/toggle_third_party_cookies"
         android:title="@string/third_party_cookies"
         android:orderInCategory="30"
         android:checkable="true"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/toggleDomStorage"
+        android:id="@+id/toggle_dom_storage"
         android:title="@string/dom_storage"
         android:orderInCategory="40"
         android:checkable="true"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/toggleSaveFormData"
+        android:id="@+id/toggle_save_form_data"
         android:title="@string/form_data"
         android:orderInCategory="50"
         android:checkable="true"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/clearCookies"
+        android:id="@+id/clear_cookies"
         android:title="@string/clear_cookies"
         android:orderInCategory="60"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/clearDomStorage"
+        android:id="@+id/clear_dom_storage"
         android:title="@string/clear_dom_storage"
         android:orderInCategory="70"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/clearFormData"
+        android:id="@+id/clear_form_data"
         android:title="@string/clear_form_data"
         android:orderInCategory="80"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/fontSize"
+        android:id="@+id/font_size"
         android:title="@string/font_size"
         android:orderInCategory="90"
         app:showAsAction="never" >
         <menu>
             <group android:checkableBehavior="single">
                 <item
-                    android:id="@+id/fontSizeTwentyFivePercent"
+                    android:id="@+id/font_size_twenty_five_percent"
                     android:title="@string/twenty_five_percent"
                     android:orderInCategory="91"
                     app:showAsAction="never" />
 
                 <item
-                    android:id="@+id/fontSizeFiftyPercent"
+                    android:id="@+id/font_size_fifty_percent"
                     android:title="@string/fifty_percent"
                     android:orderInCategory="92"
                     app:showAsAction="never" />
 
                 <item
-                    android:id="@+id/fontSizeSeventyFivePercent"
+                    android:id="@+id/font_size_seventy_five_percent"
                     android:title="@string/seventy_five_percent"
                     android:orderInCategory="93"
                     app:showAsAction="never" />
 
                 <item
-                    android:id="@+id/fontSizeOneHundredPercent"
+                    android:id="@+id/font_size_one_hundred_percent"
                     android:title="@string/one_hundred_percent"
                     android:orderInCategory="94"
                     app:showAsAction="never" />
 
                 <item
-                    android:id="@+id/fontSizeOneHundredTwentyFivePercent"
+                    android:id="@+id/font_size_one_hundred_twenty_five_percent"
                     android:title="@string/one_hundred_twenty_five_percent"
                     android:orderInCategory="95"
                     app:showAsAction="never" />
 
                 <item
-                    android:id="@+id/fontSizeOneHundredFiftyPercent"
+                    android:id="@+id/font_size_one_hundred_fifty_percent"
                     android:title="@string/one_hundred_fifty_percent"
                     android:orderInCategory="96"
                     app:showAsAction="never" />
 
                 <item
-                    android:id="@+id/fontSizeOneHundredSeventyFivePercent"
+                    android:id="@+id/font_size_one_hundred_seventy_five_percent"
                     android:title="@string/one_hundred_seventy_five_percent"
                     android:orderInCategory="97"
                     app:showAsAction="never" />
 
                 <item
-                    android:id="@+id/fontSizeTwoHundredPercent"
+                    android:id="@+id/font_size_two_hundred_percent"
                     android:title="@string/two_hundred_percent"
                     android:orderInCategory="98"
                     app:showAsAction="never" />
         </menu>
     </item>
 
+    <item
+        android:id="@+id/display_images"
+        android:title="@string/display_images"
+        android:orderInCategory="100"
+        android:checkable="true"
+        app:showAsAction="never" />
+
     <item
         android:id="@+id/share"
         android:title="@string/share"
-        android:orderInCategory="100"
+        android:orderInCategory="110"
         app:showAsAction="never" />
 
     <item
         android:id="@+id/find_on_page"
         android:title="@string/find_on_page"
-        android:orderInCategory="110"
+        android:orderInCategory="120"
         app:showAsAction="never|collapseActionView" />
     <item
         android:id="@+id/print"
         android:title="@string/print"
-        android:orderInCategory="120"
+        android:orderInCategory="130"
         app:showAsAction="never" />
 
     <item
-        android:id="@+id/addToHomescreen"
+        android:id="@+id/add_to_homescreen"
         android:title="@string/add_to_home_screen"
-        android:orderInCategory="130"
+        android:orderInCategory="140"
         app:showAsAction="never" />
 
     <item
         android:id="@+id/refresh"
         android:title="@string/refresh"
-        android:orderInCategory="140"
+        android:orderInCategory="150"
         app:showAsAction="never" />
 
-</menu>
+</menu>
\ No newline at end of file
index dfff1a27641aaa217df5aea052e613bd34cae8d5..b7109d2e7d1fc6d34b7952c9e8b1400b64ce8cc3 100644 (file)
         <string name="one_hundred_fifty_percent">150%</string>
         <string name="one_hundred_seventy_five_percent">175%</string>
         <string name="two_hundred_percent">200%</string>
-    <string name="find_on_page">Find on Page</string>
+    <string name="display_images">Display Images</string>
     <string name="share">Share</string>
-    <string name="add_to_home_screen">Add to Home Screen</string>
+    <string name="find_on_page">Find on Page</string>
     <string name="print">Print</string>
+    <string name="add_to_home_screen">Add to Home Screen</string>
         <string name="privacy_browser_web_page">Privacy Browser Web Page</string>
     <string name="refresh">Refresh</string>
 
     <string name="domain_settings_saved">Domain settings saved</string>
     <string name="domain_deleted">Domain deleted</string>
     <string name="domain_name_instructions">*. may be prepended to a domain to include all subdomains (eg. *.stoutner.com)</string>
+    <string-array name="display_website_images_array">
+        <item>System default</item>
+        <item>Images enabled</item>
+        <item>Images disabled</item>
+    </string-array>
 
     <!-- Guide. -->
     <string name="privacy_browser_guide">Privacy Browser Guide</string>
         <string name="swipe_to_refresh_enabled_summary">Some websites don’t work well if swipe to refresh is enabled.</string>
         <string name="display_additional_app_bar_icons">Display additional app bar icons</string>
         <string name="display_additional_app_bar_icons_summary">Display icons for toggling cookies, DOM storage, and form data in the app bar if there is room.</string>
+        <string name="display_webpage_images">Display webpage images</string>
+        <string name="display_webpage_images_summary">Disable to conserve bandwidth.</string>
 
     <!-- Orbot. -->
     <string name="orbot_proxy_not_installed">Orbot proxy will not work unless Orbot is installed.</string>
index 194aa4d3dd3307b9fdd8f3925eedb489e3cdd7cf..87b2eac2a6a92c529a219c8256476d090f40274f 100644 (file)
             android:title="@string/display_additional_app_bar_icons"
             android:summary="@string/display_additional_app_bar_icons_summary"
             android:defaultValue="false" />
+
+        <SwitchPreference
+            android:key="display_webpage_images"
+            android:title="@string/display_webpage_images"
+            android:summary="@string/display_webpage_images_summary"
+            android:defaultValue="true" />
     </PreferenceCategory>
 </PreferenceScreen>
\ No newline at end of file