From ed0a4234b452924acf1602bee6578a7a84445a85 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 24 May 2017 21:25:49 -0700 Subject: [PATCH] Add controls for displaying webpage images. Implements https://redmine.stoutner.com/issues/123. --- app/src/main/assets/de/about_licenses.html | 1 + app/src/main/assets/en/about_licenses.html | 1 + app/src/main/assets/en/images/ic_image.png | Bin 0 -> 1288 bytes app/src/main/assets/es/about_licenses.html | 3 +- app/src/main/assets/it/about_licenses.html | 1 + .../main/assets/zh-rTW/about_licenses.html | 1 + .../activities/DomainSettingsActivity.java | 24 +- .../activities/DomainsActivity.java | 23 +- .../activities/MainWebViewActivity.java | 636 ++++++++++-------- .../activities/SettingsActivity.java | 2 +- .../fragments/DomainSettingsFragment.java | 70 +- .../fragments/SettingsFragment.java | 20 +- .../helpers/DomainsDatabaseHelper.java | 39 +- app/src/main/res/drawable/images_disabled.xml | 18 + app/src/main/res/drawable/images_enabled.xml | 18 + app/src/main/res/layout/domain_settings.xml | 40 +- .../main/res/menu/webview_options_menu.xml | 55 +- app/src/main/res/values/strings.xml | 12 +- app/src/main/res/xml/preferences.xml | 6 + 19 files changed, 604 insertions(+), 366 deletions(-) create mode 100644 app/src/main/assets/en/images/ic_image.png create mode 100644 app/src/main/res/drawable/images_disabled.xml create mode 100644 app/src/main/res/drawable/images_enabled.xml diff --git a/app/src/main/assets/de/about_licenses.html b/app/src/main/assets/de/about_licenses.html index 6b479aea..8f99162a 100644 --- a/app/src/main/assets/de/about_licenses.html +++ b/app/src/main/assets/de/about_licenses.html @@ -90,6 +90,7 @@

ic_folder_special.

ic_fullscreen.

ic_home.

+

ic_image.

ic_import_contacts.

ic_important_devices.

ic_info_outline.

diff --git a/app/src/main/assets/en/about_licenses.html b/app/src/main/assets/en/about_licenses.html index 4e9f8f66..01ebe5d1 100644 --- a/app/src/main/assets/en/about_licenses.html +++ b/app/src/main/assets/en/about_licenses.html @@ -84,6 +84,7 @@

ic_folder_special.

ic_fullscreen.

ic_home.

+

ic_image.

ic_import_contacts.

ic_important_devices.

ic_info_outline.

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 index 0000000000000000000000000000000000000000..3e4dc0c9d8908c1de3ee600b923887e06df6b996 GIT binary patch literal 1288 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSEX7WqAsj$Z!;#Vf4nJ zsKVHUAq>Cy;O)gc=G7MrOnNoJDQtkcV7z; zV0n3I?V?4OPTDWnu|?yeL{eZ&Sc`&P@5;lq6WS-JeV_B$_IY*n{`ulECraw-Dn9L1 ze_QP6f(nj3>+7nOXNzO<^Qo`nxDj2r$8aXYe&*8$!Vmm>d478<>x1M3<{c~3F6A+J zAE-HGxx<2M&7=K^$+`QPy7&4o-sqYj``=fpI-0%jtIgyzu@{$K?zIfOB^B!%`bMwY zui<;+^4?#Q?%p-eoj<)S<)cV}#Ez!e8B6B#KH&He?5SQZ_uR{R1IGc!W;>Ph%1dPV1_1o zp-X?6_H^x&d0l@me$Jgue|c>zW4~83&p5B(^kOfg?(J;j*Y}uf%o{9se!kZb_V#k_ zwSNX5+CT5PQz`G$UB;OW?R2Myz=h4jlaJuR$pU&w}*d4+HID&7aQ5< zeQmIQ@4V{fJ#GjLzGhv|u>QhcueHxC?oaxs#M2KHJAL$=UHklX7U#4+Bs{Cz zvX1@E)|fYMiY*SXiyoW7;4k{d{WVb4>ehL8)81I_>d!h|7^i=K(z34&yT!WiytMpN z_kewIp`G^K9?7+@7|XYc-*|5MhofL`!JPMv)t|N}M(YAaO~t?K|GnSymFK5FTRmfc z>e{+=sBqY$n0qHAl7%Y_OD}R}U1xrmrTZrPQ=CVoTH%~><6|D7o8=0^lLNJ%*tef& z6tC_po>-P|yEc@6$L6>TZ&Ll&u{X$9(rVmOYMPd$-oYFMb-(pO;vd#C&@)i&^i&RaWOjpxxTB2X6O1%lx<~CtF=}J^P)h zKL4a|*|zhCX4*c`D}SW@B>r2ECy1SXNo=}pa!?Tej?*)@TunVc@LKh#-#}*2>qaH9^T(P!5))k0SLkRVCwb%crTje zfjKB0U%kYq!}MXZqx_`h74LPKJ}d>Yo_7NU^_ut?!(Xg3TsoKcK_HhstBxJxv_^lP zUlUEdd0t$9Z?nPe-u$+!mu_oq*nj<`NeNHH@%rLp_pUXnSIzS*c7M6g=VtZfW4Ep~ z9KE;vVT#<3j$ij5iLSiMV7KJZ@w&71TD1ZeuHWx(=40eOaIfoe@5z>TO}R7Q8UD6m j*7|{34!ES;_{V(f$!(?M`g`Mmr51yytDnm{r-UW|=jli6 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/es/about_licenses.html b/app/src/main/assets/es/about_licenses.html index b34a68f3..220c15ee 100644 --- a/app/src/main/assets/es/about_licenses.html +++ b/app/src/main/assets/es/about_licenses.html @@ -46,7 +46,7 @@

Licencia

Navegador Privado está liberado bajo la licencia GPLv3+. 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 git.stoutner.com.

+ El código fuente está disponible en git.stoutner.com.

Atribuciones

La lista de servidores publicitarios usados por el bloqueador de anuncios procede de pgl.yoyo.org. @@ -88,6 +88,7 @@

ic_folder_special.

ic_fullscreen.

ic_home.

+

ic_image.

ic_import_contacts.

ic_important_devices.

ic_info_outline.

diff --git a/app/src/main/assets/it/about_licenses.html b/app/src/main/assets/it/about_licenses.html index eeae2d53..2612a65c 100644 --- a/app/src/main/assets/it/about_licenses.html +++ b/app/src/main/assets/it/about_licenses.html @@ -90,6 +90,7 @@

ic_folder_special.

ic_fullscreen.

ic_home.

+

ic_image.

ic_import_contacts.

ic_important_devices.

ic_info_outline.

diff --git a/app/src/main/assets/zh-rTW/about_licenses.html b/app/src/main/assets/zh-rTW/about_licenses.html index 0af91d73..9b32ce20 100644 --- a/app/src/main/assets/zh-rTW/about_licenses.html +++ b/app/src/main/assets/zh-rTW/about_licenses.html @@ -84,6 +84,7 @@

ic_folder_special.

ic_fullscreen.

ic_home.

+

ic_image.

ic_import_contacts.

ic_important_devices.

ic_info_outline.

diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainSettingsActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainSettingsActivity.java index ccb444a7..49364db3 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainSettingsActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainSettingsActivity.java @@ -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); diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java index 2500fe9e..320cddb8 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java @@ -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(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index 01978f46..0c80f526 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -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. diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/SettingsActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/SettingsActivity.java index 9c82f070..075d5ece 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/SettingsActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/SettingsActivity.java @@ -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); diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java b/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java index bdd0302d..4416d301 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java @@ -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 userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.user_agent_entries, android.R.layout.simple_spinner_item); final ArrayAdapter userAgentEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.user_agent_entry_values, android.R.layout.simple_spinner_item); ArrayAdapter fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.default_font_size_entries, android.R.layout.simple_spinner_item); ArrayAdapter fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.default_font_size_entry_values, android.R.layout.simple_spinner_item); + final ArrayAdapter 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; } } diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java b/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java index dcc54893..2ca68461 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java @@ -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; diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java index 0e1448b4..f6bd47ad 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java @@ -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 index 00000000..bd8526c0 --- /dev/null +++ b/app/src/main/res/drawable/images_disabled.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/images_enabled.xml b/app/src/main/res/drawable/images_enabled.xml new file mode 100644 index 00000000..ee3387bc --- /dev/null +++ b/app/src/main/res/drawable/images_enabled.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/app/src/main/res/layout/domain_settings.xml b/app/src/main/res/layout/domain_settings.xml index 6878c15f..cdda48e8 100644 --- a/app/src/main/res/layout/domain_settings.xml +++ b/app/src/main/res/layout/domain_settings.xml @@ -40,7 +40,7 @@ + android:orientation="vertical" > + android:orientation="horizontal" > + android:orientation="horizontal" > + android:labelFor="@+id/domain_settings_custom_user_agent_edittext" /> + android:textSize="13sp" /> + android:layout_marginBottom="14dp" /> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/webview_options_menu.xml b/app/src/main/res/menu/webview_options_menu.xml index d2d57432..df62da64 100644 --- a/app/src/main/res/menu/webview_options_menu.xml +++ b/app/src/main/res/menu/webview_options_menu.xml @@ -25,59 +25,59 @@ tools:context=".activities.MainWebViewActivity"> @@ -85,49 +85,49 @@ @@ -135,33 +135,40 @@ + + - + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dfff1a27..b7109d2e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -121,10 +121,11 @@ 150% 175% 200% - Find on Page + Display Images Share - Add to Home Screen + Find on Page Print + Add to Home Screen Privacy Browser Web Page Refresh @@ -194,6 +195,11 @@ Domain settings saved Domain deleted *. may be prepended to a domain to include all subdomains (eg. *.stoutner.com) + + System default + Images enabled + Images disabled + Privacy Browser Guide @@ -331,6 +337,8 @@ Some websites don’t work well if swipe to refresh is enabled. Display additional app bar icons Display icons for toggling cookies, DOM storage, and form data in the app bar if there is room. + Display webpage images + Disable to conserve bandwidth. Orbot proxy will not work unless Orbot is installed. diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 194aa4d3..87b2eac2 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -189,5 +189,11 @@ android:title="@string/display_additional_app_bar_icons" android:summary="@string/display_additional_app_bar_icons_summary" android:defaultValue="false" /> + + \ No newline at end of file -- 2.43.0