private ForegroundColorSpan initialGrayColorSpan;
private ForegroundColorSpan finalGrayColorSpan;
+ // The drawer header padding variables are used in `onCreate()` and `onConfigurationChanged()`.
+ private int drawerHeaderPaddingLeftAndRight;
+ private int drawerHeaderPaddingTop;
+ private int drawerHeaderPaddingBottom;
+
// `sslErrorHandler` is used in `onCreate()`, `onSslErrorCancel()`, and `onSslErrorProceed`.
private SslErrorHandler sslErrorHandler;
float screenDensity = resources.getDisplayMetrics().density;
// Calculate the drawer header padding. This is used to move the text in the drawer headers below any cutouts.
- int drawerHeaderPaddingLeftAndRight = (int) (15 * screenDensity);
- int drawerHeaderPaddingTop = statusBarPixelSize + (int) (4 * screenDensity);
- int drawerHeaderPaddingBottom = (int) (8 * screenDensity);
+ drawerHeaderPaddingLeftAndRight = (int) (15 * screenDensity);
+ drawerHeaderPaddingTop = statusBarPixelSize + (int) (4 * screenDensity);
+ drawerHeaderPaddingBottom = (int) (8 * screenDensity);
- // The drawer listener 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) {
// 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.
+ // Only display `mainWebView` if the progress bar is gone. This prevents the display of the `WebView` while it is still loading.
if (progressBar.getVisibility() == View.GONE) {
mainWebView.setVisibility(View.VISIBLE);
}
// Check to see if Privacy Browser is waiting on Orbot.
if (!waitingForOrbot) { // We are not waiting on Orbot, so we need to process the URL.
- // We need to update `formattedUrlString` at the beginning of the load, so that if the user toggles JavaScript during the load the new website is reloaded.
+ // The formatted URL string must be updated at the beginning of the load, so that if the user toggles JavaScript during the load the new website is reloaded.
formattedUrlString = url;
// Display the formatted URL text.
// Apply the domain settings. This clears any settings from the previous domain.
applyDomainSettings(formattedUrlString, true, false);
} else { // `WebView` has loaded a webpage.
- // Set `formattedUrlString`.
- formattedUrlString = url;
+ // Set the formatted URL string. Getting the URL from the WebView instead of using the one provided by `onPageFinished` makes websites like YouTube function correctly.
+ formattedUrlString = mainWebView.getUrl();
- // Only update `urlTextBox` if the user is not typing in it.
+ // Only update the URL text box if the user is not typing in it.
if (!urlTextBox.hasFocus()) {
// Display the formatted URL text.
urlTextBox.setText(formattedUrlString);
shareIntent.setType("text/plain");
// Make it so.
- startActivity(Intent.createChooser(shareIntent, "Share URL"));
+ startActivity(Intent.createChooser(shareIntent, getString(R.string.share_url)));
+ return true;
+
+ case R.id.open_with:
+ // Convert the URL to an URI.
+ Uri shareUri = Uri.parse(formattedUrlString);
+
+ // Get the host.
+ String shareHost = shareUri.getHost();
+
+ // Create the open with intent with `ACTION_VIEW`.
+ Intent openWithIntent = new Intent(Intent.ACTION_VIEW);
+
+ // Set the data based on the host.
+ if ((shareHost != null) && (shareHost.endsWith("youtube.com") || shareHost.equals("play.google.com") || shareHost.equals("f-droid.org"))) { // Handle App URLs.
+ // Set the URI but not the MIME type. This should open all available apps.
+ openWithIntent.setData(shareUri);
+ } else { // Handle a generic URL.
+ // Set the URI and the MIME type. `"text/html"` should load browser options.
+ openWithIntent.setDataAndType(shareUri, "text/html");
+ }
+
+ // Flag the intent to open in a new task.
+ openWithIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Show the chooser.
+ startActivity(Intent.createChooser(openWithIntent, getString(R.string.open_with)));
return true;
case R.id.find_on_page:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- // Reload the ad for the free flavor if we not in full screen mode.
+ // Get the status bar pixel size.
+ int statusBarResourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
+ int statusBarPixelSize = getResources().getDimensionPixelSize(statusBarResourceId);
+
+ // Get the resource density.
+ float screenDensity = getResources().getDisplayMetrics().density;
+
+ // Recalculate the drawer header padding.
+ drawerHeaderPaddingLeftAndRight = (int) (15 * screenDensity);
+ drawerHeaderPaddingTop = statusBarPixelSize + (int) (4 * screenDensity);
+ drawerHeaderPaddingBottom = (int) (8 * screenDensity);
+
+ // Reload the ad for the free flavor if 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_unit_id));
// Create a download intent. Not specifying the action type will display the maximum number of options.
Intent downloadIntent = new Intent();
- // Set the URI and the mime type. `"*/*"` will display the maximum number of options.
+ // Set the URI and the MIME type. Specifying `text/html` displays a good number of options.
downloadIntent.setDataAndType(Uri.parse(url), "text/html");
// Flag the intent to open in a new task.