import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
-import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import com.stoutner.privacybrowser.dialogs.EditBookmarkDialog;
import com.stoutner.privacybrowser.dialogs.EditBookmarkFolderDialog;
import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog;
-import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog;
import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog;
import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog;
import com.stoutner.privacybrowser.dialogs.ViewSslCertificateDialog;
import java.util.Map;
import java.util.Set;
-// TODO. Store up reloads for tabs that are not visible.
// TODO. New tabs are white in dark mode.
// AppCompatActivity from android.support.v7.app.AppCompatActivity must be used to have access to the SupportActionBar until the minimum API is >= 21.
public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener,
DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener,
- EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener, WebViewTabFragment.NewTabListener,
- PinnedMismatchDialog.PinnedMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener {
-
- // `darkTheme` is public static so it can be accessed from everywhere.
- public static boolean darkTheme;
-
- // `allowScreenshots` is public static so it can be accessed from everywhere. It is also used in `onCreate()`.
- public static boolean allowScreenshots;
+ EditBookmarkFolderDialog.EditBookmarkFolderListener, NavigationView.OnNavigationItemSelectedListener, WebViewTabFragment.NewTabListener {
// `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`.
public static String orbotStatus;
- // The WebView pager adapter is accessed from `PinnedMismatchDialog`. It is also used in `onCreate()`, `onResume()`, and `addTab()`.
+ // The WebView pager adapter is accessed from `HttpAuthenticationDialog`, `PinnedMismatchDialog`, and `SslCertificateErrorDialog`. It is also used in `onCreate()`, `onResume()`, and `addTab()`.
public static WebViewPagerAdapter webViewPagerAdapter;
- // `reloadOnRestart` is public static so it can be accessed from `SettingsFragment`. It is used in `onRestart()`
- public static boolean reloadOnRestart;
-
// The load URL on restart variables are public static so they can be accessed from `BookmarksActivity`. They are used in `onRestart()`.
public static boolean loadUrlOnRestart;
public static String urlToLoadOnRestart;
// `restartFromBookmarksActivity` is public static so it can be accessed from `BookmarksActivity`. It is also used in `onRestart()`.
public static boolean restartFromBookmarksActivity;
- // The blocklist versions are public static so they can be accessed from `AboutTabFragment`. They are also used in `onCreate()`.
- public static String easyListVersion;
- public static String easyPrivacyVersion;
- public static String fanboysAnnoyanceVersion;
- public static String fanboysSocialVersion;
- public static String ultraPrivacyVersion;
-
// `currentBookmarksFolder` is public static so it can be accessed from `BookmarksActivity`. It is also used in `onCreate()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`,
// `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
public static String currentBookmarksFolder;
- // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, `onSslMismatchBack()`, and `applyDomainSettings()`.
- private boolean navigatingHistory; // TODO.
-
// The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`,
// `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxyThroughOrbot()`, and `applyDomainSettings()`.
private NestedScrollWebView currentWebView;
// `customHeader` is used in `onCreate()`, `onOptionsItemSelected()`, `onCreateContextMenu()`, and `loadUrl()`.
private final Map<String, String> customHeaders = new HashMap<>();
- // `firstPartyCookiesEnabled` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onDownloadImage()`, `onDownloadFile()`, and `applyDomainSettings()`.
- private boolean firstPartyCookiesEnabled;
-
- // 'homepage' is used in `onCreate()`, `onNavigationItemSelected()`, and `applyProxyThroughOrbot()`.
- private String homepage; // TODO ?
-
- // `searchURL` is used in `loadURLFromTextBox()` and `applyProxyThroughOrbot()`.
- private String searchURL; // TODO ?
+ // The search URL is set in `applyProxyThroughOrbot()` and used in `onCreate()`, `onNewIntent()`, `loadURLFromTextBox()`, and `initializeWebView()`.
+ private String searchURL;
// The options menu is set in `onCreateOptionsMenu()` and used in `onOptionsItemSelected()`, `updatePrivacyIcons()`, and `initializeWebView()`.
private Menu optionsMenu;
- // TODO. This could probably be removed.
- // The blocklist helper is used in `onCreate()` and `WebViewPagerAdapter`.
- private BlockListHelper blockListHelper;
-
- // The blocklists are populated in `onCreate()` and accessed from `WebViewPagerAdapter`.
+ // The blocklists are populated in `onCreate()` and accessed from `initializeWebView()`.
private ArrayList<List<String[]>> easyList;
private ArrayList<List<String[]>> easyPrivacy;
private ArrayList<List<String[]>> fanboysAnnoyanceList;
private ArrayList<List<String[]>> fanboysSocialList;
private ArrayList<List<String[]>> ultraPrivacy;
- // The blocklist menu items are used in `onCreateOptionsMenu()`, `onPrepareOptionsMenu()`, and `initializeWebView()`. // TODO.
- private MenuItem blocklistsMenuItem;
- private MenuItem easyListMenuItem;
- private MenuItem easyPrivacyMenuItem;
- private MenuItem fanboysAnnoyanceListMenuItem;
- private MenuItem fanboysSocialBlockingListMenuItem;
- private MenuItem ultraPrivacyMenuItem;
- private MenuItem blockAllThirdPartyRequestsMenuItem;
-
// `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`.
private String webViewDefaultUserAgent;
// `proxyThroughOrbot` is used in `onRestart()`, `onOptionsItemSelected()`, `applyAppSettings()`, and `applyProxyThroughOrbot()`.
private boolean proxyThroughOrbot;
- // `incognitoModeEnabled` is used in `onCreate()` and `applyAppSettings()`.
- private boolean incognitoModeEnabled; // TODO.
+ // The incognito mode is set in `applyAppSettings()` and used in `initializeWebView()`.
+ private boolean incognitoModeEnabled;
- // `fullScreenBrowsingModeEnabled` is used in `onCreate()` and `applyAppSettings()`.
- private boolean fullScreenBrowsingModeEnabled; // TODO.
+ // The full screen browsing mode tracker is set it `applyAppSettings()` and used in `initializeWebView()`.
+ private boolean fullScreenBrowsingModeEnabled;
// `inFullScreenBrowsingMode` is used in `onCreate()`, `onConfigurationChanged()`, and `applyAppSettings()`.
private boolean inFullScreenBrowsingMode;
- // Hide app bar is used in `onCreate()` and `applyAppSettings()`.
- private boolean hideAppBar; // TODO.
+ // The hide app bar tracker is used in `applyAppSettings()` and `initializeWebView()`.
+ private boolean hideAppBar;
// `reapplyDomainSettingsOnRestart` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, and `onAddDomain()`, .
private boolean reapplyDomainSettingsOnRestart;
// `displayingFullScreenVideo` is used in `onCreate()` and `onResume()`.
private boolean displayingFullScreenVideo;
- // `downloadWithExternalApp` is used in `onCreate()`, `onCreateContextMenu()`, and `applyDomainSettings()`.
- private boolean downloadWithExternalApp; // TODO.
-
// `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`.
private BroadcastReceiver orbotStatusBroadcastReceiver;
// `waitingForOrbot` is used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`.
private boolean waitingForOrbot;
- // `domainSettingsJavaScriptEnabled` is used in `onOptionsItemSelected()` and `applyDomainSettings()`.
- private Boolean domainSettingsJavaScriptEnabled; // TODO.
-
- // `waitingForOrbotHtmlString` is used in `onCreate()` and `applyProxyThroughOrbot()`.
- private String waitingForOrbotHtmlString; // TODO.
-
- // `privateDataDirectoryString` is used in `onCreate()`, `onOptionsItemSelected()`, and `onNavigationItemSelected()`.
- private String privateDataDirectoryString; // TODO.
-
// The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`.
private ActionBarDrawerToggle actionBarDrawerToggle;
private int drawerHeaderPaddingTop;
private int drawerHeaderPaddingBottom;
- // `sslErrorHandler` is used in `onCreate()`, `onSslErrorCancel()`, and `onSslErrorProceed`.
- private SslErrorHandler sslErrorHandler; // TODO.
-
- // `httpAuthHandler` is used in `onCreate()`, `onHttpAuthenticationCancel()`, and `onHttpAuthenticationProceed()`.
- private static HttpAuthHandler httpAuthHandler; // TODO.
-
// `bookmarksDatabaseHelper` is used in `onCreate()`, `onDestroy`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`,
// and `loadBookmarksFolder()`.
private BookmarksDatabaseHelper bookmarksDatabaseHelper;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
// Get the theme and screenshot preferences.
- darkTheme = sharedPreferences.getBoolean("dark_theme", false);
- allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
+ boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
// Disable screenshots if not allowed.
if (!allowScreenshots) {
}
});
- // Set `waitingForOrbotHTMLString`.
- waitingForOrbotHtmlString = "<html><body><br/><center><h1>" + getString(R.string.waiting_for_orbot) + "</h1></center></body></html>";
-
// Initialize the Orbot status and the waiting for Orbot trackers.
orbotStatus = "unknown";
waitingForOrbot = false;
// Load the URL from the intent.
loadUrl(launchingIntentUriData.toString());
} else { // The is no URL in the intent.
- // Load the homepage.
- loadUrl(homepage);
+ // Select the homepage based on the proxy through Orbot status.
+ if (proxyThroughOrbot) {
+ // Load the Tor homepage.
+ loadUrl(sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value)));
+ } else {
+ // Load the normal homepage.
+ loadUrl(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value)));
+ }
}
}
}
// Register `orbotStatusBroadcastReceiver` on `this` context.
this.registerReceiver(orbotStatusBroadcastReceiver, new IntentFilter("org.torproject.android.intent.action.STATUS"));
- // Instantiate the block list helper.
- blockListHelper = new BlockListHelper();
+ // Instantiate the blocklist helper.
+ BlockListHelper blockListHelper = new BlockListHelper();
// Parse the block lists.
easyList = blockListHelper.parseBlockList(getAssets(), "blocklists/easylist.txt");
fanboysSocialList = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-social.txt");
ultraPrivacy = blockListHelper.parseBlockList(getAssets(), "blocklists/ultraprivacy.txt");
- // Store the list versions.
- easyListVersion = easyList.get(0).get(0)[0];
- easyPrivacyVersion = easyPrivacy.get(0).get(0)[0];
- fanboysAnnoyanceVersion = fanboysAnnoyanceList.get(0).get(0)[0];
- fanboysSocialVersion = fanboysSocialList.get(0).get(0)[0];
- ultraPrivacyVersion = ultraPrivacy.get(0).get(0)[0];
-
// Get handles for views that need to be modified.
DrawerLayout drawerLayout = findViewById(R.id.drawerlayout);
NavigationView navigationView = findViewById(R.id.navigationview);
@Override
public void onPageSelected(int position) {
+ // Close the find on page bar if it is open.
+ closeFindOnPage(null);
+
// Set the current WebView.
setCurrentWebView(position);
- // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled via swiping in the view pager.
+ // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled via swiping in the view pager or by creating a new tab.
if (tabLayout.getSelectedTabPosition() != position) {
- // Get a handle for the corresponding tab.
- TabLayout.Tab correspondingTab = tabLayout.getTabAt(position);
+ // Create a handler to select the tab.
+ Handler selectTabHandler = new Handler();
- // Assert that the corresponding tab is not null.
- assert correspondingTab != null;
+ // Create a runnable select the new tab.
+ Runnable selectTabRunnable = () -> {
+ // Get a handle for the tab.
+ TabLayout.Tab tab = tabLayout.getTabAt(position);
- // Select the corresponding tab.
- correspondingTab.select();
+ // Assert that the tab is not null.
+ assert tab != null;
+
+ // Select the tab.
+ tab.select();
+ };
+
+ // Select the tab layout after 100 milliseconds, which leaves enough time for a new tab to be created.
+ selectTabHandler.postDelayed(selectTabRunnable, 100);
}
}
// Initialize the default preference values the first time the program is run. `false` keeps this command from resetting any current preferences back to default.
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
- // Store the application's private data directory.
- privateDataDirectoryString = getApplicationInfo().dataDir;
- // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`.
-
- // Initialize `inFullScreenBrowsingMode`, which is always false at this point because Privacy Browser never starts in full screen browsing mode.
- inFullScreenBrowsingMode = false;
-
- // Initialize the privacy settings variables.
- firstPartyCookiesEnabled = false;
-
// Inflate a bare WebView to get the default user agent. It is not used to render content on the screen.
@SuppressLint("InflateParams") View webViewLayout = getLayoutInflater().inflate(R.layout.bare_webview, null, false);
// Apply the app settings if returning from the Settings activity.
if (reapplyAppSettingsOnRestart) {
+ // Reset the reapply app settings on restart tracker.
+ reapplyAppSettingsOnRestart = false;
+
// Apply the app settings.
applyAppSettings();
+ }
- // Reload the webpage to handle changes to night mode and displaying of images.
- if (reloadOnRestart) {
- // Reload the WebViews.
- for (int i = 0; i < webViewPagerAdapter.getCount(); i++) {
- // Get the WebView tab fragment.
- WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i);
-
- // Get the fragment view.
- View fragmentView = webViewTabFragment.getView();
-
- // Only reload the WebViews if they exist.
- if (fragmentView != null) {
- // Get the nested scroll WebView from the tab fragment.
- NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
-
- // Reload the WebView. This doesn't seem to work if for WebViews that aren't visible.
- nestedScrollWebView.reload();
- }
- }
+ // Apply the domain settings if returning from the settings or domains activity.
+ if (reapplyDomainSettingsOnRestart) {
+ // Reset the reapply domain settings on restart tracker.
+ reapplyDomainSettingsOnRestart = false;
- // Reset `reloadOnRestartBoolean`.
- reloadOnRestart = false;
- }
+ // Reapply the domain settings for each tab.
+ for (int i = 0; i < webViewPagerAdapter.getCount(); i++) {
+ // Get the WebView tab fragment.
+ WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i);
- // Reset the return from settings flag.
- reapplyAppSettingsOnRestart = false;
- }
+ // Get the fragment view.
+ View fragmentView = webViewTabFragment.getView();
- // TODO apply to all the tabs.
- // Apply the domain settings if returning from the Domains activity.
- if (reapplyDomainSettingsOnRestart) {
- // Reset the current domain name so the domain settings will be reapplied.
- currentWebView.resetCurrentDomainName();
+ // Only reload the WebViews if they exist.
+ if (fragmentView != null) {
+ // Get the nested scroll WebView from the tab fragment.
+ NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
- // Reapply the domain settings.
- applyDomainSettings(currentWebView, currentWebView.getUrl(), false, true); // TODO.
+ // Reset the current domain name so the domain settings will be reapplied.
+ nestedScrollWebView.resetCurrentDomainName();
- // Reset the reapply domain settings on restart tracker.
- reapplyDomainSettingsOnRestart = false;
+ // Reapply the domain settings.
+ applyDomainSettings(nestedScrollWebView, nestedScrollWebView.getUrl(), false, true);
+ }
+ }
}
- // Load the URL on restart (used when loading a bookmark.
+ // Load the URL on restart (used when loading a bookmark).
if (loadUrlOnRestart) {
// Load the specified URL.
loadUrl(urlToLoadOnRestart);
currentWebView.getSettings().setUseWideViewPort(false);
// Load a waiting page. `null` specifies no encoding, which defaults to ASCII.
- currentWebView.loadData(waitingForOrbotHtmlString, "text/html", null);
+ currentWebView.loadData("<html><body><br/><center><h1>" + getString(R.string.waiting_for_orbot) + "</h1></center></body></html>", "text/html", null);
}
if (displayingFullScreenVideo || inFullScreenBrowsingMode) {
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.
MenuItem 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
// Get the shared preference values.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- // Get the status of the additional AppBar icons.
+ // Get the dark theme and app bar preferences..
boolean displayAdditionalAppBarIcons = sharedPreferences.getBoolean("display_additional_app_bar_icons", false);
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
// Set the status of the additional app bar icons. Setting the refresh menu item to `SHOW_AS_ACTION_ALWAYS` makes it appear even on small devices like phones.
if (displayAdditionalAppBarIcons) {
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 blocklistsMenuItem = menu.findItem(R.id.blocklists);
+ 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 blockAllThirdPartyRequestsMenuItem = 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);
thirdPartyCookiesMenuItem.setChecked(cookieManager.acceptThirdPartyCookies(currentWebView));
// Enable third-party cookies if first-party cookies are enabled.
- thirdPartyCookiesMenuItem.setEnabled(firstPartyCookiesEnabled);
+ thirdPartyCookiesMenuItem.setEnabled(cookieManager.acceptCookie());
}
// Enable DOM Storage if JavaScript is enabled.
}
// Set the status of the menu item checkboxes.
- firstPartyCookiesMenuItem.setChecked(firstPartyCookiesEnabled);
+ firstPartyCookiesMenuItem.setChecked(cookieManager.acceptCookie());
proxyThroughOrbotMenuItem.setChecked(proxyThroughOrbot);
// Enable Clear Cookies if there are any.
clearCookiesMenuItem.setEnabled(cookieManager.hasCookies());
+ // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`.
+ String privateDataDirectoryString = getApplicationInfo().dataDir;
+
// Get a count of the number of files in the Local Storage directory.
File localStorageDirectory = new File (privateDataDirectoryString + "/app_webview/Local Storage/");
int localStorageDirectoryNumberOfFiles = 0;
@Override
// Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled.
@SuppressLint("SetJavaScriptEnabled")
- // removeAllCookies is deprecated, but it is required for API < 21.
- @SuppressWarnings("deprecation")
public boolean onOptionsItemSelected(MenuItem menuItem) {
// Reenter full screen browsing mode if it was interrupted by the options menu. <https://redmine.stoutner.com/issues/389>
if (inFullScreenBrowsingMode) {
// Display a `Snackbar`.
if (currentWebView.getSettings().getJavaScriptEnabled()) { // JavaScrip is enabled.
Snackbar.make(findViewById(R.id.webviewpager), R.string.javascript_enabled, Snackbar.LENGTH_SHORT).show();
- } else if (firstPartyCookiesEnabled) { // JavaScript is disabled, but first-party cookies are enabled.
+ } else if (cookieManager.acceptCookie()) { // JavaScript is disabled, but first-party cookies are enabled.
Snackbar.make(findViewById(R.id.webviewpager), R.string.javascript_disabled, Snackbar.LENGTH_SHORT).show();
} else { // Privacy mode.
Snackbar.make(findViewById(R.id.webviewpager), R.string.privacy_mode, Snackbar.LENGTH_SHORT).show();
// Reapply the domain settings on returning to `MainWebViewActivity`.
reapplyDomainSettingsOnRestart = true;
- // TODO. Move these to `putExtra`. The certificate can be stored as strings.
- // Store the current SSL certificate and IP addresses in the domains activity.
- DomainsActivity.currentSslCertificate = currentWebView.getCertificate();
- DomainsActivity.currentIpAddresses = currentWebView.getCurrentIpAddresses();
-
// Create an intent to launch the domains activity.
Intent domainsIntent = new Intent(this, DomainsActivity.class);
domainsIntent.putExtra("close_on_back", true);
domainsIntent.putExtra("current_url", currentWebView.getUrl());
+ // Get the current certificate.
+ SslCertificate sslCertificate = currentWebView.getCertificate();
+
+ // Check to see if the SSL certificate is populated.
+ if (sslCertificate != null) {
+ // Extract the certificate to strings.
+ String issuedToCName = sslCertificate.getIssuedTo().getCName();
+ String issuedToOName = sslCertificate.getIssuedTo().getOName();
+ String issuedToUName = sslCertificate.getIssuedTo().getUName();
+ String issuedByCName = sslCertificate.getIssuedBy().getCName();
+ String issuedByOName = sslCertificate.getIssuedBy().getOName();
+ String issuedByUName = sslCertificate.getIssuedBy().getUName();
+ long startDateLong = sslCertificate.getValidNotBeforeDate().getTime();
+ long endDateLong = sslCertificate.getValidNotAfterDate().getTime();
+
+ // Add the certificate to the intent.
+ domainsIntent.putExtra("ssl_issued_to_cname", issuedToCName);
+ domainsIntent.putExtra("ssl_issued_to_oname", issuedToOName);
+ domainsIntent.putExtra("ssl_issued_to_uname", issuedToUName);
+ domainsIntent.putExtra("ssl_issued_by_cname", issuedByCName);
+ domainsIntent.putExtra("ssl_issued_by_oname", issuedByOName);
+ domainsIntent.putExtra("ssl_issued_by_uname", issuedByUName);
+ domainsIntent.putExtra("ssl_start_date", startDateLong);
+ domainsIntent.putExtra("ssl_end_date", endDateLong);
+ }
+
+ // Check to see if the current IP addresses have been received.
+ if (currentWebView.hasCurrentIpAddresses()) {
+ // Add the current IP addresses to the intent.
+ domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
+ }
+
// Make it so.
startActivity(domainsIntent);
} else { // Add a new domain.
// Create the domain and store the database ID.
int newDomainDatabaseId = domainsDatabaseHelper.addDomain(currentDomain);
- // TODO. Move these to `putExtra`. The certificate can be stored as strings.
- // Store the current SSL certificate and IP addresses in the domains activity.
- DomainsActivity.currentSslCertificate = currentWebView.getCertificate();
- DomainsActivity.currentIpAddresses = currentWebView.getCurrentIpAddresses();
-
// Create an intent to launch the domains activity.
Intent domainsIntent = new Intent(this, DomainsActivity.class);
domainsIntent.putExtra("close_on_back", true);
domainsIntent.putExtra("current_url", currentWebView.getUrl());
+ // Get the current certificate.
+ SslCertificate sslCertificate = currentWebView.getCertificate();
+
+ // Check to see if the SSL certificate is populated.
+ if (sslCertificate != null) {
+ // Extract the certificate to strings.
+ String issuedToCName = sslCertificate.getIssuedTo().getCName();
+ String issuedToOName = sslCertificate.getIssuedTo().getOName();
+ String issuedToUName = sslCertificate.getIssuedTo().getUName();
+ String issuedByCName = sslCertificate.getIssuedBy().getCName();
+ String issuedByOName = sslCertificate.getIssuedBy().getOName();
+ String issuedByUName = sslCertificate.getIssuedBy().getUName();
+ long startDateLong = sslCertificate.getValidNotBeforeDate().getTime();
+ long endDateLong = sslCertificate.getValidNotAfterDate().getTime();
+
+ // Add the certificate to the intent.
+ domainsIntent.putExtra("ssl_issued_to_cname", issuedToCName);
+ domainsIntent.putExtra("ssl_issued_to_oname", issuedToOName);
+ domainsIntent.putExtra("ssl_issued_to_uname", issuedToUName);
+ domainsIntent.putExtra("ssl_issued_by_cname", issuedByCName);
+ domainsIntent.putExtra("ssl_issued_by_oname", issuedByOName);
+ domainsIntent.putExtra("ssl_issued_by_uname", issuedByUName);
+ domainsIntent.putExtra("ssl_start_date", startDateLong);
+ domainsIntent.putExtra("ssl_end_date", endDateLong);
+ }
+
+ // Check to see if the current IP addresses have been received.
+ if (currentWebView.hasCurrentIpAddresses()) {
+ // Add the current IP addresses to the intent.
+ domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
+ }
+
// Make it so.
startActivity(domainsIntent);
}
return true;
case R.id.toggle_first_party_cookies:
- // Switch the status of firstPartyCookiesEnabled.
- firstPartyCookiesEnabled = !firstPartyCookiesEnabled;
+ // Switch the first-party cookie status.
+ cookieManager.setAcceptCookie(!cookieManager.acceptCookie());
- // Update the menu checkbox.
- menuItem.setChecked(firstPartyCookiesEnabled);
+ // Store the first-party cookie status.
+ currentWebView.setAcceptFirstPartyCookies(cookieManager.acceptCookie());
- // Apply the new cookie status.
- cookieManager.setAcceptCookie(firstPartyCookiesEnabled);
+ // Update the menu checkbox.
+ menuItem.setChecked(cookieManager.acceptCookie());
// Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step.
updatePrivacyIcons(true);
- // Display a `Snackbar`.
- if (firstPartyCookiesEnabled) { // First-party cookies are enabled.
+ // Display a snackbar.
+ if (cookieManager.acceptCookie()) { // First-party cookies are enabled.
Snackbar.make(findViewById(R.id.webviewpager), R.string.first_party_cookies_enabled, Snackbar.LENGTH_SHORT).show();
} else if (currentWebView.getSettings().getJavaScriptEnabled()) { // JavaScript is still enabled.
Snackbar.make(findViewById(R.id.webviewpager), R.string.first_party_cookies_disabled, Snackbar.LENGTH_SHORT).show();
@SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`.
@Override
public void onDismissed(Snackbar snackbar, int event) {
- switch (event) {
- // The user pushed the undo button.
- case Snackbar.Callback.DISMISS_EVENT_ACTION:
- // Do nothing.
- break;
-
- // The snackbar was dismissed without the undo button being pushed.
- default:
- // `cookieManager.removeAllCookie()` varies by SDK.
- if (Build.VERSION.SDK_INT < 21) {
- cookieManager.removeAllCookie();
- } else {
- cookieManager.removeAllCookies(null);
- }
+ if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { // The snackbar was dismissed without the undo button being pushed.
+ // Delete the cookies, which command varies by SDK.
+ if (Build.VERSION.SDK_INT < 21) {
+ cookieManager.removeAllCookie();
+ } else {
+ cookieManager.removeAllCookies(null);
+ }
}
}
})
@SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`.
@Override
public void onDismissed(Snackbar snackbar, int event) {
- switch (event) {
- // The user pushed the undo button.
- case Snackbar.Callback.DISMISS_EVENT_ACTION:
- // Do nothing.
- break;
-
- // The snackbar was dismissed without the undo button being pushed.
- default:
- // Delete the DOM Storage.
- WebStorage webStorage = WebStorage.getInstance();
- webStorage.deleteAllData();
-
- // Initialize a handler to manually delete the DOM storage files and directories.
- Handler deleteDomStorageHandler = new Handler();
-
- // Setup a runnable to manually delete the DOM storage files and directories.
- Runnable deleteDomStorageRunnable = () -> {
- try {
- // Get a handle for the runtime.
- Runtime runtime = Runtime.getRuntime();
-
- // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly.
- Process deleteLocalStorageProcess = runtime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"});
-
- // Multiple commands must be used because `Runtime.exec()` does not like `*`.
- Process deleteIndexProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB");
- Process deleteQuotaManagerProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager");
- Process deleteQuotaManagerJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal");
- Process deleteDatabasesProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases");
-
- // Wait for the processes to finish.
- deleteLocalStorageProcess.waitFor();
- deleteIndexProcess.waitFor();
- deleteQuotaManagerProcess.waitFor();
- deleteQuotaManagerJournalProcess.waitFor();
- deleteDatabasesProcess.waitFor();
- } catch (Exception exception) {
- // Do nothing if an error is thrown.
- }
- };
-
- // Manually delete the DOM storage files after 200 milliseconds.
- deleteDomStorageHandler.postDelayed(deleteDomStorageRunnable, 200);
+ if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { // The snackbar was dismissed without the undo button being pushed.
+ // Delete the DOM Storage.
+ WebStorage webStorage = WebStorage.getInstance();
+ webStorage.deleteAllData();
+
+ // Initialize a handler to manually delete the DOM storage files and directories.
+ Handler deleteDomStorageHandler = new Handler();
+
+ // Setup a runnable to manually delete the DOM storage files and directories.
+ Runnable deleteDomStorageRunnable = () -> {
+ try {
+ // Get a handle for the runtime.
+ Runtime runtime = Runtime.getRuntime();
+
+ // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`,
+ // which links to `/data/data/com.stoutner.privacybrowser.standard`.
+ String privateDataDirectoryString = getApplicationInfo().dataDir;
+
+ // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly.
+ Process deleteLocalStorageProcess = runtime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"});
+
+ // Multiple commands must be used because `Runtime.exec()` does not like `*`.
+ Process deleteIndexProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB");
+ Process deleteQuotaManagerProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager");
+ Process deleteQuotaManagerJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal");
+ Process deleteDatabasesProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases");
+
+ // Wait for the processes to finish.
+ deleteLocalStorageProcess.waitFor();
+ deleteIndexProcess.waitFor();
+ deleteQuotaManagerProcess.waitFor();
+ deleteQuotaManagerJournalProcess.waitFor();
+ deleteDatabasesProcess.waitFor();
+ } catch (Exception exception) {
+ // Do nothing if an error is thrown.
+ }
+ };
+
+ // Manually delete the DOM storage files after 200 milliseconds.
+ deleteDomStorageHandler.postDelayed(deleteDomStorageRunnable, 200);
}
}
})
@SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`.
@Override
public void onDismissed(Snackbar snackbar, int event) {
- switch (event) {
- // The user pushed the undo button.
- case Snackbar.Callback.DISMISS_EVENT_ACTION:
- // Do nothing.
- break;
-
- // The snackbar was dismissed without the `Undo` button being pushed.
- default:
- // Delete the form data.
- WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(getApplicationContext());
- mainWebViewDatabase.clearFormData();
+ if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { // The snackbar was dismissed without the undo button being pushed.
+ // Delete the form data.
+ WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(getApplicationContext());
+ mainWebViewDatabase.clearFormData();
}
}
})
currentWebView.getSettings().setJavaScriptEnabled(true);
} else if (currentWebView.getDomainSettingsApplied()) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings.
// Apply the JavaScript preference that was stored the last time domain settings were loaded.
- currentWebView.getSettings().setJavaScriptEnabled(domainSettingsJavaScriptEnabled); // TODO.
+ currentWebView.getSettings().setJavaScriptEnabled(currentWebView.getDomainSettingsJavaScriptEnabled());
} else { // Night mode is disabled and domain settings are not applied. Set JavaScript according to the global preference.
// Apply the JavaScript preference.
currentWebView.getSettings().setJavaScriptEnabled(sharedPreferences.getBoolean("javascript", false));
LinearLayout findOnPageLinearLayout = findViewById(R.id.find_on_page_linearlayout);
EditText findOnPageEditText = findViewById(R.id.find_on_page_edittext);
+ // Set the minimum height of the find on page linear layout to match the toolbar.
+ findOnPageLinearLayout.setMinimumHeight(toolbar.getHeight());
+
// Hide the toolbar.
toolbar.setVisibility(View.GONE);
return true;
case R.id.print:
- // Get a `PrintManager` instance.
+ // Get a print manager instance.
PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
- // Create a print document adapter form the current WebView.
- PrintDocumentAdapter printDocumentAdapter = currentWebView.createPrintDocumentAdapter();
-
- // Remove the lint error below that `printManager` might be `null`.
+ // Remove the lint error below that print manager might be null.
assert printManager != null;
- // Print the document. The print attributes are `null`.
+ // Create a print document adapter from the current WebView.
+ PrintDocumentAdapter printDocumentAdapter = currentWebView.createPrintDocumentAdapter();
+
+ // Print the document.
printManager.print(getString(R.string.privacy_browser_web_page), printDocumentAdapter, null);
return true;
}
// removeAllCookies is deprecated, but it is required for API < 21.
- @SuppressWarnings("deprecation")
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
// Get the menu item ID.
int menuItemId = menuItem.getItemId();
+ // Get a handle for the shared preferences.
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
// Run the commands that correspond to the selected menu item.
switch (menuItemId) {
case R.id.close_tab:
bookmarksCursor.close();
bookmarksDatabaseHelper.close();
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-
// Get the status of the clear everything preference.
boolean clearEverything = sharedPreferences.getBoolean("clear_everything", true);
// Get a handle for the runtime.
Runtime runtime = Runtime.getRuntime();
+ // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`,
+ // which links to `/data/data/com.stoutner.privacybrowser.standard`.
+ String privateDataDirectoryString = getApplicationInfo().dataDir;
+
// Clear cookies.
if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) {
// The command to remove cookies changed slightly in API 21.
break;
case R.id.home:
- loadUrl(homepage);
+ // Select the homepage based on the proxy through Orbot status.
+ if (proxyThroughOrbot) {
+ // Load the Tor homepage.
+ loadUrl(sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value)));
+ } else {
+ // Load the normal homepage.
+ loadUrl(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value)));
+ }
break;
case R.id.back:
// Reset the current domain name so that navigation works if third-party requests are blocked.
currentWebView.resetCurrentDomainName();
- // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
- navigatingHistory = true;
+ // Set navigating history so that the domain settings are applied when the new URL is loaded.
+ currentWebView.setNavigatingHistory(true);
// Load the previous website in the history.
currentWebView.goBack();
// Reset the current domain name so that navigation works if third-party requests are blocked.
currentWebView.resetCurrentDomainName();
- // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
- navigatingHistory = true;
+ // Set navigating history so that the domain settings are applied when the new URL is loaded.
+ currentWebView.setNavigatingHistory(true);
// Load the next website in the history.
currentWebView.goForward();
break;
case R.id.history:
- // Get the `WebBackForwardList`.
- WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+ // Instantiate the URL history dialog.
+ DialogFragment urlHistoryDialogFragment = UrlHistoryDialog.loadBackForwardList(currentWebView.getWebViewFragmentId());
- // Show the URL history dialog and name this instance `R.string.history`.
- DialogFragment urlHistoryDialogFragment = UrlHistoryDialog.loadBackForwardList(this, webBackForwardList);
+ // Show the URL history dialog.
urlHistoryDialogFragment.show(getSupportFragmentManager(), getString(R.string.history));
break;
// Set the flag to reapply the domain settings on restart when returning from Domain Settings.
reapplyDomainSettingsOnRestart = true;
- // TODO. Move these to `putExtra`. The certificate can be stored as strings.
- // Store the current SSL certificate and IP addresses in the domains activity.
- DomainsActivity.currentSslCertificate = currentWebView.getCertificate();
- DomainsActivity.currentIpAddresses = currentWebView.getCurrentIpAddresses();
-
// Launch the domains activity.
Intent domainsIntent = new Intent(this, DomainsActivity.class);
// Add the extra information to the intent.
domainsIntent.putExtra("current_url", currentWebView.getUrl());
+ // Get the current certificate.
+ SslCertificate sslCertificate = currentWebView.getCertificate();
+
+ // Check to see if the SSL certificate is populated.
+ if (sslCertificate != null) {
+ // Extract the certificate to strings.
+ String issuedToCName = sslCertificate.getIssuedTo().getCName();
+ String issuedToOName = sslCertificate.getIssuedTo().getOName();
+ String issuedToUName = sslCertificate.getIssuedTo().getUName();
+ String issuedByCName = sslCertificate.getIssuedBy().getCName();
+ String issuedByOName = sslCertificate.getIssuedBy().getOName();
+ String issuedByUName = sslCertificate.getIssuedBy().getUName();
+ long startDateLong = sslCertificate.getValidNotBeforeDate().getTime();
+ long endDateLong = sslCertificate.getValidNotAfterDate().getTime();
+
+ // Add the certificate to the intent.
+ domainsIntent.putExtra("ssl_issued_to_cname", issuedToCName);
+ domainsIntent.putExtra("ssl_issued_to_oname", issuedToOName);
+ domainsIntent.putExtra("ssl_issued_to_uname", issuedToUName);
+ domainsIntent.putExtra("ssl_issued_by_cname", issuedByCName);
+ domainsIntent.putExtra("ssl_issued_by_oname", issuedByOName);
+ domainsIntent.putExtra("ssl_issued_by_uname", issuedByUName);
+ domainsIntent.putExtra("ssl_start_date", startDateLong);
+ domainsIntent.putExtra("ssl_end_date", endDateLong);
+ }
+
+ // Check to see if the current IP addresses have been received.
+ if (currentWebView.hasCurrentIpAddresses()) {
+ // Add the current IP addresses to the intent.
+ domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses());
+ }
+
// Make it so.
startActivity(domainsIntent);
break;
break;
case R.id.about:
- // Launch `AboutActivity`.
+ // Create an intent to launch the about activity.
Intent aboutIntent = new Intent(this, AboutActivity.class);
+
+ // Create a string array for the blocklist versions.
+ String[] blocklistVersions = new String[] {easyList.get(0).get(0)[0], easyPrivacy.get(0).get(0)[0], fanboysAnnoyanceList.get(0).get(0)[0], fanboysSocialList.get(0).get(0)[0],
+ ultraPrivacy.get(0).get(0)[0]};
+
+ // Add the blocklist versions to the intent.
+ aboutIntent.putExtra("blocklist_versions", blocklistVersions);
+
+ // Make it so.
startActivity(aboutIntent);
break;
}
final String imageUrl;
final String linkUrl;
- // Get handles for the the clipboard and fragment managers.
+ // Get handles for the system managers.
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
FragmentManager fragmentManager = getSupportFragmentManager();
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
// Remove the lint errors below that the clipboard manager might be null.
assert clipboardManager != null;
// Add a Download URL entry.
menu.add(R.string.download_url).setOnMenuItemClickListener((MenuItem item) -> {
// Check if the download should be processed by an external app.
- if (downloadWithExternalApp) { // Download with an external app.
+ if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app.
openUrlWithExternalApp(linkUrl);
} else { // Download with Android's download manager.
// Check to see if the storage permission has already been granted.
// Add a Download Image entry.
menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> {
// Check if the download should be processed by an external app.
- if (downloadWithExternalApp) { // Download with an external app.
+ if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app.
openUrlWithExternalApp(imageUrl);
} else { // Download with Android's download manager.
// Check to see if the storage permission has already been granted.
// Add a `Download Image` entry.
menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> {
// Check if the download should be processed by an external app.
- if (downloadWithExternalApp) { // Download with an external app.
+ if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app.
openUrlWithExternalApp(imageUrl);
} else { // Download with Android's download manager.
// Check to see if the storage permission has already been granted.
// Parse `imageUrl`.
DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(imageUrl));
+ // Get a handle for the cookie manager.
+ CookieManager cookieManager = CookieManager.getInstance();
+
// Pass cookies to download manager if cookies are enabled. This is required to download images from websites that require a login.
// Code contributed 2017 Hendrik Knackstedt. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
- if (firstPartyCookiesEnabled) {
+ if (cookieManager.acceptCookie()) {
// Get the cookies for `imageUrl`.
- String cookies = CookieManager.getInstance().getCookie(imageUrl);
+ String cookies = cookieManager.getCookie(imageUrl);
// Add the cookies to `downloadRequest`. In the HTTP request header, cookies are named `Cookie`.
downloadRequest.addRequestHeader("Cookie", cookies);
// Parse `downloadUrl`.
DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(downloadUrl));
+ // Get a handle for the cookie manager.
+ CookieManager cookieManager = CookieManager.getInstance();
+
// Pass cookies to download manager if cookies are enabled. This is required to download files from websites that require a login.
// Code contributed 2017 Hendrik Knackstedt. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
- if (firstPartyCookiesEnabled) {
+ if (cookieManager.acceptCookie()) {
// Get the cookies for `downloadUrl`.
- String cookies = CookieManager.getInstance().getCookie(downloadUrl);
+ String cookies = cookieManager.getCookie(downloadUrl);
// Add the cookies to `downloadRequest`. In the HTTP request header, cookies are named `Cookie`.
downloadRequest.addRequestHeader("Cookie", cookies);
}
}
- @Override
- public void onHttpAuthenticationCancel() {
- // Cancel the `HttpAuthHandler`.
- httpAuthHandler.cancel();
- }
-
- @Override
- public void onHttpAuthenticationProceed(DialogFragment dialogFragment) {
- // Get handles for the `EditTexts`.
- EditText usernameEditText = dialogFragment.getDialog().findViewById(R.id.http_authentication_username);
- EditText passwordEditText = dialogFragment.getDialog().findViewById(R.id.http_authentication_password);
-
- // Proceed with the HTTP authentication.
- httpAuthHandler.proceed(usernameEditText.getText().toString(), passwordEditText.getText().toString());
- }
-
- @Override
- public void onSslErrorCancel() { // TODO. How to handle this with multiple tabs? There could be multiple errors at once.
- sslErrorHandler.cancel();
- }
-
- @Override
- public void onSslErrorProceed() { // TODO. How to handle this with multiple tabs? There could be multiple errors at once.
- sslErrorHandler.proceed();
- }
-
- @Override
- public void onPinnedMismatchBack() { // TODO. Move this logic to the dialog.
- if (currentWebView.canGoBack()) { // There is a back page in the history.
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
-
- // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
- navigatingHistory = true; // TODO.
-
- // Go back.
- currentWebView.goBack();
- } else { // There are no pages to go back to.
- // Load a blank page
- loadUrl("");
- }
- }
-
- @Override
- public void onPinnedMismatchProceed() { // TODO. Move this logic to the dialog.
- // Do not check the pinned information for this domain again until the domain changes.
- currentWebView.setIgnorePinnedDomainInformation(true);
- }
-
- @Override
- public void onUrlHistoryEntrySelected(int moveBackOrForwardSteps) {
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
-
- // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
- navigatingHistory = true;
-
- // Load the history entry.
- currentWebView.goBackOrForward(moveBackOrForwardSteps);
- }
-
- @Override
- public void onClearHistory() {
- // Clear the history.
- currentWebView.clearHistory();
- }
-
// Override `onBackPressed` to handle the navigation drawer and and the WebView.
@Override
public void onBackPressed() {
// Reset the current domain name so that navigation works if third-party requests are blocked.
currentWebView.resetCurrentDomainName();
- // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
- navigatingHistory = true;
+ // Set navigating history so that the domain settings are applied when the new URL is loaded.
+ currentWebView.setNavigatingHistory(true);
// Go back.
currentWebView.goBack();
- } else { // There isn't anything to do in Privacy Browser.
- // Pass `onBackPressed()` to the system.
- super.onBackPressed();
+ } else { // There is nothing else to do.
+ // Load a blank website.
+ loadUrl("");
}
}
proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
hideAppBar = sharedPreferences.getBoolean("hide_app_bar", true);
- downloadWithExternalApp = sharedPreferences.getBoolean("download_with_external_app", false);
- // Get handles for the views that need to be modified. `getSupportActionBar()` must be used until the minimum API >= 21.
+ // Get handles for the views that need to be modified.
FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout);
ActionBar actionBar = getSupportActionBar();
+ LinearLayout tabsLinearLayout = findViewById(R.id.tabs_linearlayout);
- // Remove the incorrect lint warnings below that the action bar might be null.
+ // Remove the incorrect lint warning below that the action bar might be null.
assert actionBar != null;
// Apply the proxy through Orbot settings.
if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) { // Privacy Browser is currently in full screen browsing mode.
// Update the visibility of the app bar, which might have changed in the settings.
if (hideAppBar) {
+ // Hide the tab linear layout.
+ tabsLinearLayout.setVisibility(View.GONE);
+
+ // Hide the action bar.
actionBar.hide();
} else {
+ // Show the tab linear layout.
+ tabsLinearLayout.setVisibility(View.VISIBLE);
+
+ // Show the action bar.
actionBar.show();
}
// Reset the full screen tracker, which could be true if Privacy Browser was in full screen mode before entering settings and full screen browsing was disabled.
inFullScreenBrowsingMode = false;
- // Show the app bar.
+ // Show the tab linear layout.
+ tabsLinearLayout.setVisibility(View.VISIBLE);
+
+ // Show the action bar.
actionBar.show();
// Show the banner ad in the free flavor.
// `reloadWebsite` is used if returning from the Domains activity. Otherwise JavaScript might not function correctly if it is newly enabled.
@SuppressLint("SetJavaScriptEnabled")
- private boolean applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetFavoriteIcon, boolean reloadWebsite) {
+ private boolean applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetTab, boolean reloadWebsite) {
// Store a copy of the current user agent to track changes for the return boolean.
String initialUserAgent = nestedScrollWebView.getSettings().getUserAgentString();
nestedScrollWebView.clearPinnedIpAddresses();
// Reset the favorite icon if specified.
- if (resetFavoriteIcon) {
+ if (resetTab) {
// Initialize the favorite icon.
nestedScrollWebView.initializeFavoriteIcon();
+ // Get the current page position.
+ int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId());
+
// Get a handle for the tab layout.
TabLayout tabLayout = findViewById(R.id.tablayout);
- // Get the current tab.
- TabLayout.Tab currentTab = tabLayout.getTabAt(tabLayout.getSelectedTabPosition()); // TODO. We need to get the tab for this WebView, which might not be the current tab.
+ // Get the corresponding tab.
+ TabLayout.Tab tab = tabLayout.getTabAt(currentPagePosition);
- // Remove the warning below that the current tab might be null.
- assert currentTab != null;
+ // Remove the warning below that the tab might be null.
+ assert tab != null;
- // Get the current tab custom view.
- View currentTabCustomView = currentTab.getCustomView();
+ // Get the tab custom view.
+ View tabCustomView = tab.getCustomView();
- // Remove the warning below that the current tab custom view might be null.
- assert currentTabCustomView != null;
+ // Remove the warning below that the tab custom view might be null.
+ assert tabCustomView != null;
- // Get the current tab favorite icon image view.
- ImageView currentTabFavoriteIconImageView = currentTabCustomView.findViewById(R.id.favorite_icon_imageview);
+ // Get the tab views.
+ ImageView tabFavoriteIconImageView = tabCustomView.findViewById(R.id.favorite_icon_imageview);
+ TextView tabTitleTextView = tabCustomView.findViewById(R.id.title_textview);
// Set the default favorite icon as the favorite icon for this tab.
- currentTabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteOrDefaultIcon(), 64, 64, true));
+ tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteOrDefaultIcon(), 64, 64, true));
+
+ // Set the loading title text.
+ tabTitleTextView.setText(R.string.loading);
}
// Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
boolean displayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
// Get a handle for the cookie manager.
CookieManager cookieManager = CookieManager.getInstance();
// Get the settings from the cursor.
nestedScrollWebView.setDomainSettingsDatabaseId(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID)));
- boolean domainJavaScriptEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1);
- firstPartyCookiesEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1); // TODO.
+ nestedScrollWebView.setDomainSettingsJavaScriptEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1);
+ nestedScrollWebView.setAcceptFirstPartyCookies(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1);
boolean domainThirdPartyCookiesEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1);
nestedScrollWebView.getSettings().setDomStorageEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1);
// Form data can be removed once the minimum API >= 26.
break;
}
- // TODO.
- // Store the domain JavaScript status. This is used by the options menu night mode toggle.
- domainSettingsJavaScriptEnabled = domainJavaScriptEnabled;
-
// Enable JavaScript if night mode is enabled.
if (nestedScrollWebView.getNightMode()) {
// Enable JavaScript.
nestedScrollWebView.getSettings().setJavaScriptEnabled(true);
} else {
// Set JavaScript according to the domain settings.
- nestedScrollWebView.getSettings().setJavaScriptEnabled(domainJavaScriptEnabled);
+ nestedScrollWebView.getSettings().setJavaScriptEnabled(nestedScrollWebView.getDomainSettingsJavaScriptEnabled());
}
- // Close `currentHostDomainSettingsCursor`.
+ // Close the current host domain settings cursor.
currentDomainSettingsCursor.close();
// Apply the domain settings.
- cookieManager.setAcceptCookie(firstPartyCookiesEnabled); //TODO This could be bad.
+ cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies());
+
+ // Set third-party cookies status if API >= 21.
+ if (Build.VERSION.SDK_INT >= 21) {
+ cookieManager.setAcceptThirdPartyCookies(nestedScrollWebView, domainThirdPartyCookiesEnabled);
+ }
// Apply the form data setting if the API < 26.
if (Build.VERSION.SDK_INT < 26) {
nestedScrollWebView.getSettings().setTextZoom(fontSize);
}
- // Set third-party cookies status if API >= 21.
- if (Build.VERSION.SDK_INT >= 21) {
- cookieManager.setAcceptThirdPartyCookies(nestedScrollWebView, domainThirdPartyCookiesEnabled);
- }
-
// Only set the user agent if the webpage is not currently loading. Otherwise, changing the user agent on redirects can cause the original website to reload.
// <https://redmine.stoutner.com/issues/160>
if (nestedScrollWebView.getProgress() == 100) { // A URL is not loading.
} else { // The new URL does not have custom domain settings. Load the defaults.
// Store the values from the shared preferences.
boolean defaultJavaScriptEnabled = sharedPreferences.getBoolean("javascript", false);
- firstPartyCookiesEnabled = sharedPreferences.getBoolean("first_party_cookies", false); // TODO.
+ nestedScrollWebView.setAcceptFirstPartyCookies(sharedPreferences.getBoolean("first_party_cookies", false));
boolean defaultThirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false);
nestedScrollWebView.getSettings().setDomStorageEnabled(sharedPreferences.getBoolean("dom_storage", false));
boolean saveFormData = sharedPreferences.getBoolean("save_form_data", false); // Form data can be removed once the minimum API >= 26.
}
// Apply the default settings.
- cookieManager.setAcceptCookie(firstPartyCookiesEnabled); // TODO.
+ cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies());
nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
+ // Apply the form data setting if the API < 26.
+ if (Build.VERSION.SDK_INT < 26) {
+ nestedScrollWebView.getSettings().setSaveFormData(saveFormData);
+ }
+
// Store the swipe to refresh status in the nested scroll WebView.
nestedScrollWebView.setSwipeToRefresh(defaultSwipeToRefresh);
// Apply swipe to refresh according to the default.
swipeRefreshLayout.setEnabled(defaultSwipeToRefresh);
- // Apply the form data setting if the API < 26.
- if (Build.VERSION.SDK_INT < 26) {
- nestedScrollWebView.getSettings().setSaveFormData(saveFormData);
- }
-
// Reset the pinned variables.
nestedScrollWebView.setDomainSettingsDatabaseId(-1);
// Get a handle for the shared preferences.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- // Get the search preferences.
- String homepageString = sharedPreferences.getString("homepage", getString(R.string.homepage_default_value));
- String torHomepageString = sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value));
+ // Get the search and theme preferences.
String torSearchString = sharedPreferences.getString("tor_search", getString(R.string.tor_search_default_value));
String torSearchCustomUrlString = sharedPreferences.getString("tor_search_custom_url", getString(R.string.tor_search_custom_url_default_value));
String searchString = sharedPreferences.getString("search", getString(R.string.search_default_value));
String searchCustomUrlString = sharedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value));
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
// Get a handle for the action bar. `getSupportActionBar()` must be used until the minimum API >= 21.
ActionBar actionBar = getSupportActionBar();
// Set the homepage, search, and proxy options.
if (proxyThroughOrbot) { // Set the Tor options.
- // Set `torHomepageString` as `homepage`.
- homepage = torHomepageString;
-
// Set the search URL.
if (torSearchString.equals("Custom URL")) { // Get the custom URL string.
searchURL = torSearchCustomUrlString;
currentWebView.getSettings().setUseWideViewPort(false);
// Load a waiting page. `null` specifies no encoding, which defaults to ASCII.
- currentWebView.loadData(waitingForOrbotHtmlString, "text/html", null);
+ currentWebView.loadData("<html><body><br/><center><h1>" + getString(R.string.waiting_for_orbot) + "</h1></center></body></html>", "text/html", null);
} else if (reloadWebsite) { // Orbot is ready and the website should be reloaded.
// Reload the website.
currentWebView.reload();
}
} else { // Set the non-Tor options.
- // Set `homepageString` as `homepage`.
- homepage = homepageString;
-
// Set the search URL.
if (searchString.equals("Custom URL")) { // Get the custom URL string.
searchURL = searchCustomUrlString;
private void updatePrivacyIcons(boolean runInvalidateOptionsMenu) {
// Only update the privacy icons if the options menu and the current WebView have already been populated.
if ((optionsMenu != null) && (currentWebView != null)) {
+ // Get a handle for the shared preferences.
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+ // Get the theme and screenshot preferences.
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
+
// Get handles for the menu items.
MenuItem privacyMenuItem = optionsMenu.findItem(R.id.toggle_javascript);
MenuItem firstPartyCookiesMenuItem = optionsMenu.findItem(R.id.toggle_first_party_cookies);
// Update the privacy icon.
if (currentWebView.getSettings().getJavaScriptEnabled()) { // JavaScript is enabled.
privacyMenuItem.setIcon(R.drawable.javascript_enabled);
- } else if (firstPartyCookiesEnabled) { // JavaScript is disabled but cookies are enabled.
+ } else if (currentWebView.getAcceptFirstPartyCookies()) { // JavaScript is disabled but cookies are enabled.
privacyMenuItem.setIcon(R.drawable.warning);
} else { // All the dangerous features are disabled.
privacyMenuItem.setIcon(R.drawable.privacy_mode);
}
// Update the first-party cookies icon.
- if (firstPartyCookiesEnabled) { // First-party cookies are enabled.
+ if (currentWebView.getAcceptFirstPartyCookies()) { // First-party cookies are enabled.
firstPartyCookiesMenuItem.setIcon(R.drawable.cookies_enabled);
} else { // First-party cookies are disabled.
if (darkTheme) {
assert newTab != null;
// Set a custom view on the new tab.
- newTab.setCustomView(R.layout.custom_tab_view);
+ newTab.setCustomView(R.layout.tab_custom_view);
// Add the new WebView page.
webViewPagerAdapter.addPage(newTabNumber, webViewPager);
}
private void setCurrentWebView(int pageNumber) {
+ // Get a handle for the shared preferences.
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+ // Get the theme preference.
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
+
// Get handles for the URL views.
RelativeLayout urlRelativeLayout = findViewById(R.id.url_relativelayout);
EditText urlEditText = findViewById(R.id.url_edittext);
// Get the fragment view.
View fragmentView = webViewTabFragment.getView();
- // Remove the incorrect lint warning below that the fragment view might be null.
- assert fragmentView != null;
-
- // Store the current WebView.
- currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
+ // Set the current WebView if the fragment view is not null.
+ if (fragmentView != null) {
+ // Store the current WebView.
+ currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
- // Update the status of swipe to refresh.
- if (currentWebView.getSwipeToRefresh()) { // Swipe to refresh is enabled.
- if (Build.VERSION.SDK_INT >= 23) { // For API >= 23, swipe refresh layout is continuously updated with an on scroll change listener and only enabled if the WebView is scrolled to the top.
- // Enable the swipe refresh layout if the WebView is scrolled all the way to the top.
- swipeRefreshLayout.setEnabled(currentWebView.getY() == 0);
- } else {
- // Enable the swipe refresh layout.
- swipeRefreshLayout.setEnabled(true);
+ // Update the status of swipe to refresh.
+ if (currentWebView.getSwipeToRefresh()) { // Swipe to refresh is enabled.
+ if (Build.VERSION.SDK_INT >= 23) { // For API >= 23, swipe refresh layout is continuously updated with an on scroll change listener and only enabled if the WebView is scrolled to the top.
+ // Enable the swipe refresh layout if the WebView is scrolled all the way to the top.
+ swipeRefreshLayout.setEnabled(currentWebView.getY() == 0);
+ } else {
+ // Enable the swipe refresh layout.
+ swipeRefreshLayout.setEnabled(true);
+ }
+ } else { // Swipe to refresh is disabled.
+ // Disable the swipe refresh layout.
+ swipeRefreshLayout.setEnabled(false);
}
- } else { // Swipe to refresh is disabled.
- // Disable the swipe refresh layout.
- swipeRefreshLayout.setEnabled(false);
- }
- // Update the privacy icons. `true` redraws the icons in the app bar.
- updatePrivacyIcons(true);
+ // Get a handle for the cookie manager.
+ CookieManager cookieManager = CookieManager.getInstance();
- // Clear the focus from the URL text box.
- urlEditText.clearFocus();
+ // Set the first-party cookie status.
+ cookieManager.setAcceptCookie(currentWebView.getAcceptFirstPartyCookies());
- // Get a handle for the input method manager.
- InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ // Update the privacy icons. `true` redraws the icons in the app bar.
+ updatePrivacyIcons(true);
- // Remove the lint warning below that the input method manager might be null.
- assert inputMethodManager != null;
+ // Clear the focus from the URL text box.
+ urlEditText.clearFocus();
- // Hide the soft keyboard.
- inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0);
+ // Get a handle for the input method manager.
+ InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- // Display the current URL in the URL text box.
- urlEditText.setText(currentWebView.getUrl());
+ // Remove the lint warning below that the input method manager might be null.
+ assert inputMethodManager != null;
- // Highlight the URL text.
- highlightUrlText();
+ // Hide the soft keyboard.
+ inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0);
- // Set the background to indicate the domain settings status.
- if (currentWebView.getDomainSettingsApplied()) {
- // Set a green background on the URL relative layout to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21.
- if (darkTheme) {
- urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue));
+ // Display the current URL in the URL text box.
+ urlEditText.setText(currentWebView.getUrl());
+
+ // Highlight the URL text.
+ highlightUrlText();
+
+ // Set the background to indicate the domain settings status.
+ if (currentWebView.getDomainSettingsApplied()) {
+ // Set a green background on the URL relative layout to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21.
+ if (darkTheme) {
+ urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue));
+ } else {
+ urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green));
+ }
} else {
- urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green));
+ urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent));
}
- } else {
- urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent));
}
}
DrawerLayout drawerLayout = findViewById(R.id.drawerlayout);
RelativeLayout mainContentRelativeLayout = findViewById(R.id.main_content_relativelayout);
ActionBar actionBar = getSupportActionBar();
+ LinearLayout tabsLinearLayout = findViewById(R.id.tabs_linearlayout);
EditText urlEditText = findViewById(R.id.url_edittext);
TabLayout tabLayout = findViewById(R.id.tablayout);
SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swiperefreshlayout);
- // Remove the incorrect lint warnings below that the some of the views might be null.
+ // Remove the incorrect lint warning below that the action bar might be null.
assert actionBar != null;
// Get a handle for the activity
// Get a handle for the input method manager.
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ // Instantiate the blocklist helper.
+ BlockListHelper blockListHelper = new BlockListHelper();
+
// Remove the lint warning below that the input method manager might be null.
assert inputMethodManager != null;
if (inFullScreenBrowsingMode) { // Switch to full screen mode.
// Hide the app bar if specified.
if (hideAppBar) {
+ // Close the find on page bar if it is visible.
+ closeFindOnPage(null);
+
+ // Hide the tab linear layout.
+ tabsLinearLayout.setVisibility(View.GONE);
+
+ // Hide the action bar.
actionBar.hide();
}
rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
} else { // Switch to normal viewing mode.
- // Show the app bar.
+ // Show the tab linear layout.
+ tabsLinearLayout.setVisibility(View.VISIBLE);
+
+ // Show the action bar.
actionBar.show();
// Show the banner ad in the free flavor.
}
};
- // Displaying of `mainWebView` after 500 milliseconds.
+ // Display the WebView after 500 milliseconds.
displayWebViewHandler.postDelayed(displayWebViewRunnable, 500);
});
}
// Get the current tab.
TabLayout.Tab tab = tabLayout.getTabAt(currentPosition);
- // Remove the lint warning below that the current tab might be null.
- assert tab != null;
-
- // Get the custom view from the tab.
- View tabView = tab.getCustomView();
-
- // Remove the incorrect warning below that the current tab view might be null.
- assert tabView != null;
+ // Check to see if the tab has been populated.
+ if (tab != null) {
+ // Get the custom view from the tab.
+ View tabView = tab.getCustomView();
- // Get the favorite icon image view from the tab.
- ImageView tabFavoriteIconImageView = tabView.findViewById(R.id.favorite_icon_imageview);
+ // Check to see if the custom tab view has been populated.
+ if (tabView != null) {
+ // Get the favorite icon image view from the tab.
+ ImageView tabFavoriteIconImageView = tabView.findViewById(R.id.favorite_icon_imageview);
- // Display the favorite icon in the tab.
- tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true));
+ // Display the favorite icon in the tab.
+ tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true));
+ }
+ }
}
}
// Show the main content relative layout.
mainContentRelativeLayout.setVisibility(View.VISIBLE);
- // Apply the appropriate full screen mode the `SYSTEM_UI` flags.
+ // Apply the appropriate full screen mode flags.
if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) { // Privacy Browser is currently in full screen browsing mode.
// Hide the app bar if specified.
if (hideAppBar) {
+ // Hide the tab linear layout.
+ tabsLinearLayout.setVisibility(View.GONE);
+
+ // Hide the action bar.
actionBar.hide();
}
nestedScrollWebView.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.
- @SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("http")) { // Load the URL in Privacy Browser.
}
// Check requests against the block lists. The deprecated `shouldInterceptRequest()` must be used until minimum API >= 21.
- @SuppressWarnings("deprecation")
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
// Get a handle for the navigation view.
activity.runOnUiThread(() -> {
// Update the menu item titles.
navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- blockAllThirdPartyRequestsMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS) + " - " +
- getString(R.string.block_all_third_party_requests));
+
+ // Update the options menu if it has been populated.
+ if (optionsMenu != null) {
+ optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ optionsMenu.findItem(R.id.block_all_third_party_requests).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS) + " - " +
+ getString(R.string.block_all_third_party_requests));
+ }
});
}
activity.runOnUiThread(() -> {
// Update the menu item titles.
navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- ultraPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY) + " - " + getString(R.string.ultraprivacy));
+
+ // Update the options menu if it has been populated.
+ if (optionsMenu != null) {
+ optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ optionsMenu.findItem(R.id.ultraprivacy).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY) + " - " + getString(R.string.ultraprivacy));
+ }
});
}
activity.runOnUiThread(() -> {
// Update the menu item titles.
navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- easyListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_LIST) + " - " + getString(R.string.easylist));
+
+ // Update the options menu if it has been populated.
+ if (optionsMenu != null) {
+ optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ optionsMenu.findItem(R.id.easylist).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_LIST) + " - " + getString(R.string.easylist));
+ }
});
}
activity.runOnUiThread(() -> {
// Update the menu item titles.
navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- easyPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY) + " - " + getString(R.string.easyprivacy));
+
+ // Update the options menu if it has been populated.
+ if (optionsMenu != null) {
+ optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ optionsMenu.findItem(R.id.easyprivacy).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY) + " - " + getString(R.string.easyprivacy));
+ }
});
}
activity.runOnUiThread(() -> {
// Update the menu item titles.
navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- fanboysAnnoyanceListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST) + " - " +
- getString(R.string.fanboys_annoyance_list));
+
+ // Update the options menu if it has been populated.
+ if (optionsMenu != null) {
+ optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ optionsMenu.findItem(R.id.fanboys_annoyance_list).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST) + " - " +
+ getString(R.string.fanboys_annoyance_list));
+ }
});
}
activity.runOnUiThread(() -> {
// Update the menu item titles.
navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
- fanboysSocialBlockingListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST) + " - " +
- getString(R.string.fanboys_social_blocking_list));
+
+ // Update the options menu if it has been populated.
+ if (optionsMenu != null) {
+ optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ optionsMenu.findItem(R.id.fanboys_social_blocking_list).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST) + " - " +
+ getString(R.string.fanboys_social_blocking_list));
+ }
});
}
// Handle HTTP authentication requests.
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
- // Store `handler` so it can be accessed from `onHttpAuthenticationCancel()` and `onHttpAuthenticationProceed()`.
- httpAuthHandler = handler;
+ // Store the handler.
+ nestedScrollWebView.setHttpAuthHandler(handler);
+
+ // Instantiate an HTTP authentication dialog.
+ DialogFragment httpAuthenticationDialogFragment = HttpAuthenticationDialog.displayDialog(host, realm, nestedScrollWebView.getWebViewFragmentId());
- // Display the HTTP authentication dialog.
- DialogFragment httpAuthenticationDialogFragment = HttpAuthenticationDialog.displayDialog(host, realm);
+ // Show the HTTP authentication dialog.
httpAuthenticationDialogFragment.show(getSupportFragmentManager(), getString(R.string.http_authentication));
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ // Get the theme preference.
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
+
// Reset the list of resource requests.
nestedScrollWebView.clearResourceRequests();
// Check to see if Privacy Browser is waiting on Orbot.
if (!waitingForOrbot) { // Process the URL.
- // Display the formatted URL text.
- urlEditText.setText(url);
+ // Get the current page position.
+ int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId());
- // Apply text highlighting to `urlTextBox`.
- highlightUrlText();
+ // Update the URL text bar if the page is currently selected.
+ if (tabLayout.getSelectedTabPosition() == currentPagePosition) {
+ // Display the formatted URL text.
+ urlEditText.setText(url);
+
+ // Apply text highlighting to `urlTextBox`.
+ highlightUrlText();
+ }
// Reset the list of host IP addresses.
nestedScrollWebView.clearCurrentIpAddresses();
new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost());
// Apply any custom domain settings if the URL was loaded by navigating history.
- if (navigatingHistory) {
+ if (nestedScrollWebView.getNavigatingHistory()) {
+ // Reset navigating history.
+ nestedScrollWebView.setNavigatingHistory(false);
+
// Apply the domain settings.
boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false);
- // Reset `navigatingHistory`.
- navigatingHistory = false;
-
// Manually load the URL if the user agent has changed, which will have caused the previous URL to be reloaded.
if (userAgentChanged) {
loadUrl(url);
// Set the title.
refreshMenuItem.setTitle(R.string.stop);
- // Get the status of the additional AppBar icons.
+ // Get the app bar and theme preferences.
boolean displayAdditionalAppBarIcons = sharedPreferences.getBoolean("display_additional_app_bar_icons", false);
// If the icon is displayed in the AppBar, set it according to the theme.
nestedScrollWebView.getSettings().setUseWideViewPort(url.startsWith("http"));
}
- // Flush any cookies to persistent storage. `CookieManager` has become very lazy about flushing cookies in recent versions.
- if (firstPartyCookiesEnabled && Build.VERSION.SDK_INT >= 21) {
+ // Flush any cookies to persistent storage. The cookie manager has become very lazy about flushing cookies in recent versions.
+ if (nestedScrollWebView.getAcceptFirstPartyCookies() && Build.VERSION.SDK_INT >= 21) {
CookieManager.getInstance().flush();
}
// Reset the Refresh title.
refreshMenuItem.setTitle(R.string.refresh);
- // Get the status of the additional AppBar icons.
+ // Get the app bar and theme preferences.
boolean displayAdditionalAppBarIcons = sharedPreferences.getBoolean("display_additional_app_bar_icons", false);
+ boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
// If the icon is displayed in the AppBar, reset it according to the theme.
if (displayAdditionalAppBarIcons) {
}
}
-
// Clear the cache and history if Incognito Mode is enabled.
if (incognitoModeEnabled) {
// Clear the cache. `true` includes disk files.
// Manually delete cache folders.
try {
+ // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`,
+ // which links to `/data/data/com.stoutner.privacybrowser.standard`.
+ String privateDataDirectoryString = getApplicationInfo().dataDir;
+
// Delete the main cache directory.
Runtime.getRuntime().exec("rm -rf " + privateDataDirectoryString + "/cache");
// Update the URL text box and apply domain settings if not waiting on Orbot.
if (!waitingForOrbot) {
- // Check to see if `WebView` has set `url` to be `about:blank`.
- if (url.equals("about:blank")) { // The WebView is blank.
- // Display the hint in the URL edit text.
- urlEditText.setText("");
-
- // Request focus for `urlTextBox`.
- urlEditText.requestFocus();
-
- // Display the keyboard.
- inputMethodManager.showSoftInput(urlEditText, 0);
-
- // Hide the WebView, which causes the default background color to be displayed according to the theme.
- nestedScrollWebView.setVisibility(View.GONE);
-
- // Apply the domain settings. This clears any settings from the previous domain.
- applyDomainSettings(nestedScrollWebView, "", true, false);
- } else { // The WebView has loaded a webpage.
- // Only update the URL text box if the user is not typing in it.
- if (!urlEditText.hasFocus()) {
- // Display the final URL. Getting the URL from the WebView instead of using the one provided by `onPageFinished` makes websites like YouTube function correctly.
- urlEditText.setText(nestedScrollWebView.getUrl());
-
- // Apply text highlighting to `urlTextBox`.
- highlightUrlText();
+ // Get the current page position.
+ int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId());
+
+ // Update the URL text bar if the page is currently selected.
+ if (tabLayout.getSelectedTabPosition() == currentPagePosition) {
+ // Check to see if the URL is `about:blank`.
+ if (url.equals("about:blank")) { // The WebView is blank.
+ // Display the hint in the URL edit text.
+ urlEditText.setText("");
+
+ // Request focus for the URL text box.
+ urlEditText.requestFocus();
+
+ // Display the keyboard.
+ inputMethodManager.showSoftInput(urlEditText, 0);
+
+ // Hide the WebView, which causes the default background color to be displayed according to the theme. // TODO
+ nestedScrollWebView.setVisibility(View.GONE);
+
+ // Apply the domain settings. This clears any settings from the previous domain.
+ applyDomainSettings(nestedScrollWebView, "", true, false);
+ } else { // The WebView has loaded a webpage.
+ // Only update the URL text box if the user is not typing in it.
+ if (!urlEditText.hasFocus()) {
+ // Display the final URL. Getting the URL from the WebView instead of using the one provided by `onPageFinished()` makes websites like YouTube function correctly.
+ urlEditText.setText(nestedScrollWebView.getUrl());
+
+ // Apply text highlighting to the URL.
+ highlightUrlText();
+ }
}
}
handler.proceed();
}
} else { // Either there isn't a pinned SSL certificate or it doesn't match the current website certificate.
- // Store `handler` so it can be accesses from `onSslErrorCancel()` and `onSslErrorProceed()`.
- sslErrorHandler = handler; // TODO. We need to pass this in instead of using a static variable. Because multiple could be displayed at once from different tabs.
+ // Store the SSL error handler.
+ nestedScrollWebView.setSslErrorHandler(handler);
- // Display the SSL error `AlertDialog`.
- DialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error);
+ // Instantiate an SSL certificate error alert dialog.
+ DialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error, nestedScrollWebView.getWebViewFragmentId());
+
+ // Show the SSL certificate error dialog.
sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_error));
}
}
// Load the URL from the intent.
loadUrl(launchingIntentUriData.toString());
} else { // The is no URL in the intent.
- // Load the homepage.
- loadUrl(homepage);
+ // Select the homepage based on the proxy through Orbot status.
+ if (proxyThroughOrbot) {
+ // Load the Tor homepage.
+ loadUrl(sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value)));
+ } else {
+ // Load the normal homepage.
+ loadUrl(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value)));
+ }
}
}
}