import android.Manifest;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.app.DialogFragment;
import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
// The request items are public static so they can be accessed by `BlockListHelper`, `RequestsArrayAdapter`, and `ViewRequestsDialog`. They are also used in `onCreate()` and `onPrepareOptionsMenu()`.
public static List<String[]> resourceRequests;
public static String[] whiteListResultStringArray;
- int easyListBlockedRequests;
- int easyPrivacyBlockedRequests;
- int fanboysAnnoyanceListBlockedRequests;
- int fanboysSocialBlockingListBlockedRequests;
- int ultraPrivacyBlockedRequests;
- int thirdPartyBlockedRequests;
+ private int blockedRequests;
+ private int easyListBlockedRequests;
+ private int easyPrivacyBlockedRequests;
+ private int fanboysAnnoyanceListBlockedRequests;
+ private int fanboysSocialBlockingListBlockedRequests;
+ private int ultraPrivacyBlockedRequests;
+ private int thirdPartyBlockedRequests;
public final static int REQUEST_DISPOSITION = 0;
public final static int REQUEST_URL = 1;
// `saveFormDataEnabled` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. It can be removed once the minimum API >= 26.
private boolean saveFormDataEnabled;
- // `nightMode` is used in `onCreate()` and `applyDomainSettings()`.
+ // `nightMode` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyDomainSettings()`.
private boolean nightMode;
// `displayWebpageImagesBoolean` is used in `applyAppSettings()` and `applyDomainSettings()`.
// `searchURL` is used in `loadURLFromTextBox()` and `applyAppSettings()`.
private String searchURL;
- // The block list variables are used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyAppSettings()`.
+ // `mainMenu` is used in `onCreateOptionsMenu()` and `updatePrivacyIcons()`.
+ private Menu mainMenu;
+
+ // `refreshMenuItem` is used in `onCreate()` and `onCreateOptionsMenu()`.
+ private MenuItem refreshMenuItem;
+
+ // The blocklist menu items are used in `onCreate()`, `onCreateOptionsMenu()`, and `onPrepareOptionsMenu()`.
+ private MenuItem blocklistsMenuItem;
+ private MenuItem easyListMenuItem;
+ private MenuItem easyPrivacyMenuItem;
+ private MenuItem fanboysAnnoyanceListMenuItem;
+ private MenuItem fanboysSocialBlockingListMenuItem;
+ private MenuItem ultraPrivacyMenuItem;
+ private MenuItem blockAllThirdPartyRequestsMenuItem;
+
+ // The blocklist variables are used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, and `applyAppSettings()`.
private boolean easyListEnabled;
private boolean easyPrivacyEnabled;
private boolean fanboysAnnoyanceListEnabled;
private boolean fanboysSocialBlockingListEnabled;
private boolean ultraPrivacyEnabled;
+ // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`.
+ private String webViewDefaultUserAgent;
+
+ // `defaultCustomUserAgentString` is used in `onPrepareOptionsMenu()` and `applyDomainSettings()`.
+ private String defaultCustomUserAgentString;
+
// `privacyBrowserRuntime` is used in `onCreate()`, `onOptionsItemSelected()`, and `applyAppSettings()`.
private Runtime privacyBrowserRuntime;
// `ignorePinnedSslCertificateForDomain` is used in `onCreate()`, `onSslMismatchProceed()`, and `applyDomainSettings()`.
private boolean ignorePinnedSslCertificate;
- // `orbotStatusBroadcastReciever` is used in `onCreate()` and `onDestroy()`.
+ // `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`.
private BroadcastReceiver orbotStatusBroadcastReceiver;
// `waitingForOrbot` is used in `onCreate()`, `onResume()`, and `applyAppSettings()`.
// `domainSettingsApplied` is used in `prepareOptionsMenu()`, `applyDomainSettings()`, and `setDisplayWebpageImages()`.
private boolean domainSettingsApplied;
+ // `domainSettingsJavaScriptEnabled` is used in `onOptionsItemSelected()` and `applyDomainSettings()`.
+ private Boolean domainSettingsJavaScriptEnabled;
+
// `displayWebpageImagesInt` is used in `applyDomainSettings()` and `setDisplayWebpageImages()`.
private int displayWebpageImagesInt;
// `findOnPageEditText` is used in `onCreate()`, `onOptionsItemSelected()`, and `closeFindOnPage()`.
private EditText findOnPageEditText;
- // `mainMenu` is used in `onCreateOptionsMenu()` and `updatePrivacyIcons()`.
- private Menu mainMenu;
-
- // `refreshMenuItem` is used in `onCreate()` and `onCreateOptionsItem()`.
- private MenuItem refreshMenuItem;
-
// `displayAdditionalAppBarIcons` is used in `onCreate()` and `onCreateOptionsMenu()`.
private boolean displayAdditionalAppBarIcons;
// `pinnedDomainSslCertificate` is used in `onCreate()` and `applyDomainSettings()`.
private boolean pinnedDomainSslCertificate;
- // `bookmarksDatabaseHelper` is used in `onCreate()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
+ // `bookmarksDatabaseHelper` is used in `onCreate()`, `onDestroy`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`,
+ // and `loadBookmarksFolder()`.
private BookmarksDatabaseHelper bookmarksDatabaseHelper;
// `bookmarksListView` is used in `onCreate()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, and `loadBookmarksFolder()`.
// `bookmarksTitleTextView` is used in `onCreate()` and `loadBookmarksFolder()`.
private TextView bookmarksTitleTextView;
- // `bookmarksCursor` is used in `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
+ // `bookmarksCursor` is used in `onDestroy()`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
private Cursor bookmarksCursor;
// `bookmarksCursorAdapter` is used in `onCreateBookmark()`, `onCreateBookmarkFolder()` `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
// Store the content of the status message in `orbotStatus`.
orbotStatus = intent.getStringExtra("org.torproject.android.intent.extra.STATUS");
- // If we are waiting on Orbot, load the website now that Orbot is connected.
+ // If Privacy Browser is waiting on Orbot, load the website now that Orbot is connected.
if (orbotStatus.equals("ON") && waitingForOrbot) {
// Reset `waitingForOrbot`.
waitingForOrbot = false;
// Show the `BannerAd` in the free flavor.
if (BuildConfig.FLAVOR.contentEquals("free")) {
// Reload the ad. The AdView is destroyed and recreated, which changes the ID, every time it is reloaded to handle possible rotations.
- AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_id));
+ AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_unit_id));
}
// Remove the translucent navigation bar flag if it is set.
return true;
});
- // The `DrawerListener` is used to update the Navigation Menu.
+ // The drawer listener is used to update the navigation menu.
drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
@Override
public void onDrawerStateChanged(int newState) {
- if ((newState == DrawerLayout.STATE_SETTLING) || (newState == DrawerLayout.STATE_DRAGGING)) { // The drawer is opening or closing.
- // Calculate the total blocked requests counter.
- int totalBlockedRequests = easyListBlockedRequests + easyPrivacyBlockedRequests + fanboysAnnoyanceListBlockedRequests + fanboysSocialBlockingListBlockedRequests +
- ultraPrivacyBlockedRequests + thirdPartyBlockedRequests;
-
+ if ((newState == DrawerLayout.STATE_SETTLING) || (newState == DrawerLayout.STATE_DRAGGING)) { // A drawer is opening or closing.
// Update the back, forward, history, and requests menu items.
navigationBackMenuItem.setEnabled(mainWebView.canGoBack());
navigationForwardMenuItem.setEnabled(mainWebView.canGoForward());
navigationHistoryMenuItem.setEnabled((mainWebView.canGoBack() || mainWebView.canGoForward()));
- navigationRequestsMenuItem.setTitle(getResources().getString(R.string.requests) + " - " + totalBlockedRequests);
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
- // Hide the keyboard (if displayed) so we can see the navigation menu. `0` indicates no additional flags.
+ // Hide the keyboard (if displayed).
inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0);
- // Clear the focus from `urlTextBox` if it has it.
+ // Clear the focus from from the URL text box.
urlTextBox.clearFocus();
}
}
mainWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; " +
"style.innerHTML = '* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important;" +
"text-shadow: none !important; border: none !important;} a {color: #1565C0 !important;}'; parent.appendChild(style)})()", value -> {
- // Initialize a `Handler` to display `mainWebView`.
+ // Initialize a handler to display `mainWebView`.
Handler displayWebViewHandler = new Handler();
- // Setup a `Runnable` to display `mainWebView` after a delay to allow the CSS to be applied.
+ // Setup a runnable to display `mainWebView` after a delay to allow the CSS to be applied.
Runnable displayWebViewRunnable = () -> {
// Only display `mainWebView` if the progress bar is one. This prevents the display of the `WebView` while it is still loading.
if (progressBar.getVisibility() == View.GONE) {
}
};
- // Use `displayWebViewHandler` to delay the displaying of `mainWebView` for 500 milliseconds.
+ // Displaying of `mainWebView` after 500 milliseconds.
displayWebViewHandler.postDelayed(displayWebViewRunnable, 500);
});
}
@Override
public void onHideCustomView() {
// Unset the full screen video flag.
- displayingFullScreenVideo = true;
+ displayingFullScreenVideo = false;
// Hide `fullScreenVideoFrameLayout`.
fullScreenVideoFrameLayout.removeAllViews();
// Show the `BannerAd` in the free flavor.
if (BuildConfig.FLAVOR.contentEquals("free")) {
// Initialize the ad. The AdView is destroyed and recreated, which changes the ID, every time it is reloaded to handle possible rotations.
- AdHelper.initializeAds(findViewById(R.id.adview), getApplicationContext(), getFragmentManager(), getString(R.string.ad_id));
+ AdHelper.initializeAds(findViewById(R.id.adview), getApplicationContext(), getFragmentManager(), getString(R.string.google_app_id), getString(R.string.ad_unit_id));
}
// Remove any `SYSTEM_UI` flags from `rootCoordinatorLayout`.
// Show the ad if this is the free flavor.
if (BuildConfig.FLAVOR.contentEquals("free")) {
// Reload the ad. The AdView is destroyed and recreated, which changes the ID, every time it is reloaded to handle possible rotations.
- AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_id));
+ AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_unit_id));
}
}
// Show a dialog if the user has previously denied the permission.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
- // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_FILE.
+ // Instantiate the download location permission alert dialog and set the download type to DOWNLOAD_FILE.
DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_FILE);
// Show the download location permission alert dialog. The permission will be requested when the the dialog is closed.
// Request the permission. The download dialog will be launched by `onRequestPermissionResult()`.
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_FILE_REQUEST_CODE);
}
- } else { // The WRITE_EXTERNAL_STORAGE permission has already been granted.
+ } else { // The storage permission has already been granted.
// Get a handle for the download file alert dialog.
AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength);
saveFormDataEnabled = false; // Form data can be removed once the minimum API >= 26.
nightMode = false;
+ // Store the default user agent.
+ webViewDefaultUserAgent = mainWebView.getSettings().getUserAgentString();
+
// Initialize the WebView title.
webViewTitle = getString(R.string.no_title);
fanboysSocialVersion = fanboysSocialList.get(0).get(0)[0];
ultraPrivacyVersion = ultraPrivacy.get(0).get(0)[0];
+ // Get a handle for the activity. This is used to update the requests counter while the navigation menu is open.
+ Activity activity = this;
+
mainWebView.setWebViewClient(new WebViewClient() {
// `shouldOverrideUrlLoading` makes this `WebView` the default handler for URLs inside the app, so that links are not kicked out to other apps.
// The deprecated `shouldOverrideUrlLoading` must be used until API >= 24.
// Block third-party requests if enabled.
if (isThirdPartyRequest && blockAllThirdPartyRequests) {
- // Increment the third-party blocked requests counter.
+ // Increment the blocked requests counters.
+ blockedRequests++;
thirdPartyBlockedRequests++;
+ // Update the titles of the blocklist menu items. This must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ blocklistsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ blockAllThirdPartyRequestsMenuItem.setTitle(thirdPartyBlockedRequests + " - " + getString(R.string.block_all_third_party_requests));
+ });
+
// Add the request to the log.
resourceRequests.add(new String[]{String.valueOf(REQUEST_THIRD_PARTY), url});
// Check UltraPrivacy if it is enabled.
if (ultraPrivacyEnabled) {
if (blockListHelper.isBlocked(currentDomain, url, isThirdPartyRequest, ultraPrivacy)) {
- // Increment the UltraPrivacy blocked requests counter.
+ // Increment the blocked requests counters.
+ blockedRequests++;
ultraPrivacyBlockedRequests++;
+ // Update the titles of the blocklist menu items. This must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ blocklistsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ ultraPrivacyMenuItem.setTitle(ultraPrivacyBlockedRequests + " - " + getString(R.string.ultraprivacy));
+ });
+
// The resource request was blocked. Return an empty web resource response.
return emptyWebResourceResponse;
}
// Check EasyList if it is enabled.
if (easyListEnabled) {
if (blockListHelper.isBlocked(currentDomain, url, isThirdPartyRequest, easyList)) {
- // Increment the EasyList blocked requests counter.
+ // Increment the blocked requests counters.
+ blockedRequests++;
easyListBlockedRequests++;
+ // Update the titles of the blocklist menu items. This must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ blocklistsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ easyListMenuItem.setTitle(easyListBlockedRequests + " - " + getString(R.string.easylist));
+ });
+
// Reset the whitelist results tracker (because otherwise it will sometimes add results to the list due to a race condition).
whiteListResultStringArray = null;
// Check EasyPrivacy if it is enabled.
if (easyPrivacyEnabled) {
if (blockListHelper.isBlocked(currentDomain, url, isThirdPartyRequest, easyPrivacy)) {
- // Increment the EasyPrivacy blocked requests counter.
+ // Increment the blocked requests counters.
+ blockedRequests++;
easyPrivacyBlockedRequests++;
+ // Update the titles of the blocklist menu items. This must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ blocklistsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ easyPrivacyMenuItem.setTitle(easyPrivacyBlockedRequests + " - " + getString(R.string.easyprivacy));
+ });
+
// Reset the whitelist results tracker (because otherwise it will sometimes add results to the list due to a race condition).
whiteListResultStringArray = null;
// Check Fanboy’s Annoyance List if it is enabled.
if (fanboysAnnoyanceListEnabled) {
if (blockListHelper.isBlocked(currentDomain, url, isThirdPartyRequest, fanboysAnnoyanceList)) {
- // Increment the Fanboy's Annoyance List blocked requests counter.
+ // Increment the blocked requests counters.
+ blockedRequests++;
fanboysAnnoyanceListBlockedRequests++;
+ // Update the titles of the blocklist menu items. This must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ blocklistsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ fanboysAnnoyanceListMenuItem.setTitle(fanboysAnnoyanceListBlockedRequests + " - " + getString(R.string.fanboys_annoyance_list));
+ });
+
// Reset the whitelist results tracker (because otherwise it will sometimes add results to the list due to a race condition).
whiteListResultStringArray = null;
}
} else if (fanboysSocialBlockingListEnabled){ // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled.
if (blockListHelper.isBlocked(currentDomain, url, isThirdPartyRequest, fanboysSocialList)) {
- // Increment the Fanboy's Social Blocking List blocked requests counter.
+ // Increment the blocked requests counters.
+ blockedRequests++;
fanboysSocialBlockingListBlockedRequests++;
+ // Update the titles of the blocklist menu items. This must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ blocklistsMenuItem.setTitle(getString(R.string.requests) + " - " + blockedRequests);
+ fanboysSocialBlockingListMenuItem.setTitle(fanboysSocialBlockingListBlockedRequests + " - " + getString(R.string.fanboys_social_blocking_list));
+ });
+
// Reset the whitelist results tracker (because otherwise it will sometimes add results to the list due to a race condition).
whiteListResultStringArray = null;
// Add the request to the log because it hasn't been processed by any of the previous checks.
if (whiteListResultStringArray != null ) { // The request was processed by a whitelist.
resourceRequests.add(whiteListResultStringArray);
- } else { // The request didn't match any blocklist entry. Log it as a defult request.
+ } else { // The request didn't match any blocklist entry. Log it as a default request.
resourceRequests.add(new String[]{String.valueOf(REQUEST_DEFAULT), url});
}
resourceRequests.clear();
// Initialize the counters for requests blocked by each blocklist.
+ blockedRequests = 0;
easyListBlockedRequests = 0;
easyPrivacyBlockedRequests = 0;
fanboysAnnoyanceListBlockedRequests = 0;
// It is necessary to update `formattedUrlString` and `urlTextBox` after the page finishes loading because the final URL can change during load.
@Override
public void onPageFinished(WebView view, String url) {
+ // Reset the wide view port if it has been turned off by the waiting for Orbot message.
+ if (!waitingForOrbot) {
+ mainWebView.getSettings().setUseWideViewPort(true);
+ }
+
// Flush any cookies to persistent storage. `CookieManager` has become very lazy about flushing cookies in recent versions.
if (firstPartyCookiesEnabled && Build.VERSION.SDK_INT >= 21) {
cookieManager.flush();
// Display a message to the user if waiting for Orbot.
if (waitingForOrbot && !orbotStatus.equals("ON")) {
+ // Disable the wide view port so that the waiting for Orbot text is displayed correctly.
+ mainWebView.getSettings().setUseWideViewPort(false);
+
// Load a waiting page. `null` specifies no encoding, which defaults to ASCII.
mainWebView.loadData(waitingForOrbotHTMLString, "text/html", null);
}
// Unregister the Orbot status broadcast receiver.
this.unregisterReceiver(orbotStatusBroadcastReceiver);
+ // Close the bookmarks cursor and database.
+ bookmarksCursor.close();
+ bookmarksDatabaseHelper.close();
+
// Run the default commands.
super.onDestroy();
}
MenuItem toggleSaveFormDataMenuItem = menu.findItem(R.id.toggle_save_form_data); // Form data can be removed once the minimum API >= 26.
MenuItem clearFormDataMenuItem = menu.findItem(R.id.clear_form_data); // Form data can be removed once the minimum API >= 26.
refreshMenuItem = menu.findItem(R.id.refresh);
+ blocklistsMenuItem = menu.findItem(R.id.blocklists);
+ easyListMenuItem = menu.findItem(R.id.easylist);
+ easyPrivacyMenuItem = menu.findItem(R.id.easyprivacy);
+ fanboysAnnoyanceListMenuItem = menu.findItem(R.id.fanboys_annoyance_list);
+ fanboysSocialBlockingListMenuItem = menu.findItem(R.id.fanboys_social_blocking_list);
+ ultraPrivacyMenuItem = menu.findItem(R.id.ultraprivacy);
+ blockAllThirdPartyRequestsMenuItem = menu.findItem(R.id.block_all_third_party_requests);
MenuItem adConsentMenuItem = menu.findItem(R.id.ad_consent);
// Only display third-party cookies if API >= 21
MenuItem clearCookiesMenuItem = menu.findItem(R.id.clear_cookies);
MenuItem clearDOMStorageMenuItem = menu.findItem(R.id.clear_dom_storage);
MenuItem clearFormDataMenuItem = menu.findItem(R.id.clear_form_data); // Form data can be removed once the minimum API >= 26.
- MenuItem easyListMenuItem = menu.findItem(R.id.easylist);
- MenuItem easyPrivacyMenuItem = menu.findItem(R.id.easyprivacy);
- MenuItem fanboysAnnoyanceListMenuItem = menu.findItem(R.id.fanboys_annoyance_list);
- MenuItem fanboysSocialBlockingListMenuItem = menu.findItem(R.id.fanboys_social_blocking_list);
- MenuItem ultraPrivacyMenuItem = menu.findItem(R.id.ultraprivacy);
- MenuItem blockAllThirdParyRequestsMenuItem = menu.findItem(R.id.block_all_third_party_requests);
MenuItem fontSizeMenuItem = menu.findItem(R.id.font_size);
MenuItem swipeToRefreshMenuItem = menu.findItem(R.id.swipe_to_refresh);
MenuItem displayImagesMenuItem = menu.findItem(R.id.display_images);
+ MenuItem nightModeMenuItem = menu.findItem(R.id.night_mode);
// Set the text for the domain menu item.
if (domainSettingsApplied) {
fanboysAnnoyanceListMenuItem.setChecked(fanboysAnnoyanceListEnabled);
fanboysSocialBlockingListMenuItem.setChecked(fanboysSocialBlockingListEnabled);
ultraPrivacyMenuItem.setChecked(ultraPrivacyEnabled);
- blockAllThirdParyRequestsMenuItem.setChecked(blockAllThirdPartyRequests);
+ blockAllThirdPartyRequestsMenuItem.setChecked(blockAllThirdPartyRequests);
swipeToRefreshMenuItem.setChecked(swipeRefreshLayout.isEnabled());
displayImagesMenuItem.setChecked(mainWebView.getSettings().getLoadsImagesAutomatically());
+ nightModeMenuItem.setChecked(nightMode);
// Enable third-party cookies if first-party cookies are enabled.
toggleThirdPartyCookiesMenuItem.setEnabled(firstPartyCookiesEnabled);
// Enable Clear Data if any of the submenu items are enabled.
clearDataMenuItem.setEnabled(clearCookiesMenuItem.isEnabled() || clearDOMStorageMenuItem.isEnabled() || clearFormDataMenuItem.isEnabled());
- // Update the display names for the blocklists with the number of blocked requests.
+ // Disable Fanboy's Social Blocking List if Fanboy's Annoyance List is checked.
+ fanboysSocialBlockingListMenuItem.setEnabled(!fanboysAnnoyanceListEnabled);
+
+ // Initialize the display names for the blocklists with the number of blocked requests.
+ blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + blockedRequests);
easyListMenuItem.setTitle(easyListBlockedRequests + " - " + getString(R.string.easylist));
easyPrivacyMenuItem.setTitle(easyPrivacyBlockedRequests + " - " + getString(R.string.easyprivacy));
fanboysAnnoyanceListMenuItem.setTitle(fanboysAnnoyanceListBlockedRequests + " - " + getString(R.string.fanboys_annoyance_list));
fanboysSocialBlockingListMenuItem.setTitle(fanboysSocialBlockingListBlockedRequests + " - " + getString(R.string.fanboys_social_blocking_list));
ultraPrivacyMenuItem.setTitle(ultraPrivacyBlockedRequests + " - " + getString(R.string.ultraprivacy));
- blockAllThirdParyRequestsMenuItem.setTitle(thirdPartyBlockedRequests + " - " + getString(R.string.block_all_third_party_requests));
-
- // Disable Fanboy's Social Blocking List if Fanboy's Annoyance List is checked.
- fanboysSocialBlockingListMenuItem.setEnabled(!fanboysAnnoyanceListEnabled);
+ blockAllThirdPartyRequestsMenuItem.setTitle(thirdPartyBlockedRequests + " - " + getString(R.string.block_all_third_party_requests));
+
+ // Get the current user agent.
+ String currentUserAgent = mainWebView.getSettings().getUserAgentString();
+
+ // Select the current user agent menu item. A switch statement cannot be used because the user agents are not compile time constants.
+ if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[0])) { // Privacy Browser.
+ menu.findItem(R.id.user_agent_privacy_browser).setChecked(true);
+ } else if (currentUserAgent.equals(webViewDefaultUserAgent)) { // WebView Default.
+ menu.findItem(R.id.user_agent_webview_default).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[2])) { // Firefox on Android.
+ menu.findItem(R.id.user_agent_firefox_on_android).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[3])) { // Chrome on Android.
+ menu.findItem(R.id.user_agent_chrome_on_android).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[4])) { // Safari on iOS.
+ menu.findItem(R.id.user_agent_safari_on_ios).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[5])) { // Firefox on Linux.
+ menu.findItem(R.id.user_agent_firefox_on_linux).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[6])) { // Chromium on Linux.
+ menu.findItem(R.id.user_agent_chromium_on_linux).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[7])) { // Firefox on Windows.
+ menu.findItem(R.id.user_agent_firefox_on_windows).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[8])) { // Chrome on Windows.
+ menu.findItem(R.id.user_agent_chrome_on_windows).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[9])) { // Edge on Windows.
+ menu.findItem(R.id.user_agent_edge_on_windows).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[10])) { // Internet Explorer on Windows.
+ menu.findItem(R.id.user_agent_internet_explorer_on_windows).setChecked(true);
+ } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[11])) { // Safari on macOS.
+ menu.findItem(R.id.user_agent_safari_on_macos).setChecked(true);
+ } else { // Custom user agent.
+ menu.findItem(R.id.user_agent_custom).setChecked(true);
+ }
// Initialize font size variables.
int fontSize = mainWebView.getSettings().getTextZoom();
.show();
return true;
- case R.id.font_size_twenty_five_percent:
- mainWebView.getSettings().setTextZoom(25);
- return true;
-
- case R.id.font_size_fifty_percent:
- mainWebView.getSettings().setTextZoom(50);
- return true;
-
- case R.id.font_size_seventy_five_percent:
- mainWebView.getSettings().setTextZoom(75);
- return true;
-
- case R.id.font_size_one_hundred_percent:
- mainWebView.getSettings().setTextZoom(100);
- return true;
-
- case R.id.font_size_one_hundred_twenty_five_percent:
- mainWebView.getSettings().setTextZoom(125);
- return true;
-
- case R.id.font_size_one_hundred_fifty_percent:
- mainWebView.getSettings().setTextZoom(150);
- return true;
-
- case R.id.font_size_one_hundred_seventy_five_percent:
- mainWebView.getSettings().setTextZoom(175);
- return true;
-
- case R.id.font_size_two_hundred_percent:
- mainWebView.getSettings().setTextZoom(200);
- return true;
-
- case R.id.swipe_to_refresh:
- // Toggle swipe to refresh.
- swipeRefreshLayout.setEnabled(!swipeRefreshLayout.isEnabled());
- 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.view_source:
- // Launch the View Source activity.
- Intent viewSourceIntent = new Intent(this, ViewSourceActivity.class);
- startActivity(viewSourceIntent);
- return true;
-
case R.id.easylist:
// Toggle the EasyList status.
easyListEnabled = !easyListEnabled;
mainWebView.reload();
return true;
+ case R.id.user_agent_privacy_browser:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[0]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_webview_default:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString("");
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_firefox_on_android:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[2]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_chrome_on_android:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[3]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_safari_on_ios:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[4]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_firefox_on_linux:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[5]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_chromium_on_linux:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[6]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_firefox_on_windows:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[7]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_chrome_on_windows:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[8]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_edge_on_windows:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[9]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_internet_explorer_on_windows:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[10]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_safari_on_macos:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[11]);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.user_agent_custom:
+ // Update the user agent.
+ mainWebView.getSettings().setUserAgentString(defaultCustomUserAgentString);
+
+ // Reload the WebView.
+ mainWebView.reload();
+ return true;
+
+ case R.id.font_size_twenty_five_percent:
+ mainWebView.getSettings().setTextZoom(25);
+ return true;
+
+ case R.id.font_size_fifty_percent:
+ mainWebView.getSettings().setTextZoom(50);
+ return true;
+
+ case R.id.font_size_seventy_five_percent:
+ mainWebView.getSettings().setTextZoom(75);
+ return true;
+
+ case R.id.font_size_one_hundred_percent:
+ mainWebView.getSettings().setTextZoom(100);
+ return true;
+
+ case R.id.font_size_one_hundred_twenty_five_percent:
+ mainWebView.getSettings().setTextZoom(125);
+ return true;
+
+ case R.id.font_size_one_hundred_fifty_percent:
+ mainWebView.getSettings().setTextZoom(150);
+ return true;
+
+ case R.id.font_size_one_hundred_seventy_five_percent:
+ mainWebView.getSettings().setTextZoom(175);
+ return true;
+
+ case R.id.font_size_two_hundred_percent:
+ mainWebView.getSettings().setTextZoom(200);
+ return true;
+
+ case R.id.swipe_to_refresh:
+ // Toggle swipe to refresh.
+ swipeRefreshLayout.setEnabled(!swipeRefreshLayout.isEnabled());
+ 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.night_mode:
+ // Toggle night mode.
+ nightMode = !nightMode;
+
+ // Enable or disable JavaScript according to night mode, the global preference, and any domain settings.
+ if (nightMode) { // Night mode is enabled. Enable JavaScript.
+ // Update the global variable.
+ javaScriptEnabled = true;
+ } else if (domainSettingsApplied) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings.
+ // Get the JavaScript preference that was stored the last time domain settings were loaded.
+ javaScriptEnabled = domainSettingsJavaScriptEnabled;
+ } else { // Night mode is disabled and domain settings are not applied. Set JavaScript according to the global preference.
+ // Get a handle for the shared preference.
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+ // Get the JavaScript preference.
+ javaScriptEnabled = sharedPreferences.getBoolean("javascript_enabled", false);
+ }
+
+ // Apply the JavaScript setting to the WebView.
+ mainWebView.getSettings().setJavaScriptEnabled(javaScriptEnabled);
+
+ // Update the privacy icons.
+ updatePrivacyIcons(false);
+
+ // Reload the website.
+ mainWebView.reload();
+ return true;
+
+ case R.id.view_source:
+ // Launch the View Source activity.
+ Intent viewSourceIntent = new Intent(this, ViewSourceActivity.class);
+ startActivity(viewSourceIntent);
+ return true;
+
case R.id.share:
// Setup the share string.
String shareString = webViewTitle + " – " + urlTextBox.getText().toString();
startActivity(settingsIntent);
break;
+ case R.id.import_export:
+ // Launch the import/export activity.
+ Intent importExportIntent = new Intent (this, ImportExportActivity.class);
+ startActivity(importExportIntent);
+ break;
+
case R.id.guide:
// Launch `GuideActivity`.
Intent guideIntent = new Intent(this, GuideActivity.class);
break;
case R.id.clearAndExit:
+ // Close the bookmarks cursor and database.
+ bookmarksCursor.close();
+ bookmarksDatabaseHelper.close();
+
// Get a handle for `sharedPreferences`. `this` references the current context.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
// Reload the ad for the free flavor if we not in full screen mode.
if (BuildConfig.FLAVOR.contentEquals("free") && !inFullScreenBrowsingMode) {
// Reload the ad. The AdView is destroyed and recreated, which changes the ID, every time it is reloaded to handle possible rotations.
- AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_id));
+ AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_unit_id));
}
// `invalidateOptionsMenu` should recalculate the number of action buttons from the menu to display on the app bar, but it doesn't because of the this bug:
// Show a dialog if the user has previously denied the permission.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
- // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_FILE.
+ // Instantiate the download location permission alert dialog and set the download type to DOWNLOAD_FILE.
DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_FILE);
// Show the download location permission alert dialog. The permission will be requested when the the dialog is closed.
// Show a dialog if the user has previously denied the permission.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
- // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_IMAGE.
+ // Instantiate the download location permission alert dialog and set the download type to DOWNLOAD_IMAGE.
DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_IMAGE);
// Show the download location permission alert dialog. The permission will be requested when the dialog is closed.
// Show a dialog if the user has previously denied the permission.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
- // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_IMAGE.
+ // Instantiate the download location permission alert dialog and set the download type to DOWNLOAD_IMAGE.
DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_IMAGE);
// Show the download location permission alert dialog. The permission will be requested when the dialog is closed.
}
@Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case DOWNLOAD_FILE_REQUEST_CODE:
// Show the download file alert dialog. When the dialog closes, the correct command will be used based on the permission status.
// Set `waitingForOrbot`.
waitingForOrbot = true;
+ // Disable the wide view port so that the waiting for Orbot text is displayed correctly.
+ mainWebView.getSettings().setUseWideViewPort(false);
+
// Load a waiting page. `null` specifies no encoding, which defaults to ASCII.
mainWebView.loadData(waitingForOrbotHTMLString, "text/html", null);
}
// Show the `BannerAd` in the free flavor.
if (BuildConfig.FLAVOR.contentEquals("free")) {
// Initialize the ad. The AdView is destroyed and recreated, which changes the ID, every time it is reloaded to handle possible rotations.
- AdHelper.initializeAds(findViewById(R.id.adview), getApplicationContext(), getFragmentManager(), getString(R.string.ad_id));
+ AdHelper.initializeAds(findViewById(R.id.adview), getApplicationContext(), getFragmentManager(), getString(R.string.google_app_id), getString(R.string.ad_unit_id));
}
// Remove any `SYSTEM_UI` flags from `rootCoordinatorLayout`.
favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(favoriteIconBitmap, 64, 64, true));
}
- // 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`.
+ // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(this, null, null, 0);
// Get a full cursor from `domainsDatabaseHelper`.
// Store the general preference information.
String defaultFontSizeString = sharedPreferences.getString("default_font_size", "100");
String defaultUserAgentName = sharedPreferences.getString("user_agent", "Privacy Browser");
- String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
+ defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
nightMode = sharedPreferences.getBoolean("night_mode", false);
break;
}
- // Set `javaScriptEnabled` to be `true` if `night_mode` is `true`.
+ // Store the domain JavaScript status. This is used by the options menu night mode toggle.
+ domainSettingsJavaScriptEnabled = javaScriptEnabled;
+
+ // Enable JavaScript if night mode is enabled.
if (nightMode) {
javaScriptEnabled = true;
}
urlAppBarRelativeLayout.setBackgroundDrawable(getResources().getDrawable(R.color.transparent));
}
- // Close `domainsDatabaseHelper`.
+ // Close the domains database helper.
domainsDatabaseHelper.close();
// Remove the `onTheFlyDisplayImagesSet` flag and set the display webpage images mode. `true` indicates that custom domain settings are applied.