package com.stoutner.privacybrowser.activities;
+import android.Manifest;
import android.annotation.SuppressLint;
import android.app.DialogFragment;
import android.app.DownloadManager;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.print.PrintDocumentAdapter;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
// `ShortcutInfoCompat`, `ShortcutManagerCompat`, and `IconCompat` can be switched to the non-compat version once API >= 26.
import android.support.v4.content.pm.ShortcutInfoCompat;
import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog;
import com.stoutner.privacybrowser.dialogs.CreateHomeScreenShortcutDialog;
import com.stoutner.privacybrowser.dialogs.DownloadImageDialog;
+import com.stoutner.privacybrowser.dialogs.DownloadLocationPermissionDialog;
import com.stoutner.privacybrowser.dialogs.EditBookmarkDialog;
import com.stoutner.privacybrowser.dialogs.EditBookmarkFolderDialog;
import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog;
import java.util.Map;
import java.util.Set;
-// We need to use AppCompatActivity from android.support.v7.app.AppCompatActivity to have access to the SupportActionBar until the minimum API is >= 21.
+// 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 AddDomainDialog.AddDomainListener, CreateBookmarkDialog.CreateBookmarkListener,
CreateBookmarkFolderDialog.CreateBookmarkFolderListener, CreateHomeScreenShortcutDialog.CreateHomeScreenSchortcutListener, DownloadFileDialog.DownloadFileListener,
- DownloadImageDialog.DownloadImageListener, EditBookmarkDialog.EditBookmarkListener, EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener,
- NavigationView.OnNavigationItemSelectedListener, PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener,
- UrlHistoryDialog.UrlHistoryListener {
+ DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener,
+ EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener,
+ PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener {
// `darkTheme` is public static so it can be accessed from `AboutActivity`, `GuideActivity`, `AddDomainDialog`, `SettingsActivity`, `DomainsActivity`, `DomainsListFragment`, `BookmarksActivity`,
// `BookmarksDatabaseViewActivity`, `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `DownloadFileDialog`, `DownloadImageDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`,
// The block list variables are used in `onCreate()` and `applyAppSettings()`.
private boolean easyListEnabled;
private boolean easyPrivacyEnabled;
- private boolean fanboyAnnoyanceListEnabled;
- private boolean fanboySocialBlockingListEnabled;
+ private boolean fanboysAnnoyanceListEnabled;
+ private boolean fanboysSocialBlockingListEnabled;
// `privacyBrowserRuntime` is used in `onCreate()`, `onOptionsItemSelected()`, and `applyAppSettings()`.
private Runtime privacyBrowserRuntime;
+ // `proxyThroughOrbot` is used in `onRestart()` and `applyAppSettings()`.
+ boolean proxyThroughOrbot;
+
// `incognitoModeEnabled` is used in `onCreate()` and `applyAppSettings()`.
private boolean incognitoModeEnabled;
private boolean reapplyDomainSettingsOnRestart;
// `reapplyAppSettingsOnRestart` is used in `onNavigationItemSelected()` and `onRestart()`.
- private boolean reapplyAppSettingsOnRestert;
+ private boolean reapplyAppSettingsOnRestart;
// `currentDomainName` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onAddDomain()`, and `applyDomainSettings()`.
private String currentDomainName;
// `oldFolderNameString` is used in `onCreate()` and `onSaveEditBookmarkFolder()`.
private String oldFolderNameString;
+ // The download strings are used in `onCreate()` and `onRequestPermissionResult()`.
+ private String downloadUrl;
+ private String downloadContentDisposition;
+ private long downloadContentLength;
+
+ // `downloadImageUrl` is used in `onCreateContextMenu()` and `onRequestPermissionResult()`.
+ private String downloadImageUrl;
+
+ // The request codes are used in `onCreate()`, `onCreateContextMenu()`, `onCloseDownloadLocationPermissionDialog()`, and `onRequestPermissionResult()`.
+ private final int DOWNLOAD_FILE_REQUEST_CODE = 1;
+ private final int DOWNLOAD_IMAGE_REQUEST_CODE = 2;
+
@Override
// Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled. The whole premise of Privacy Browser is built around an understanding of these dangers.
- @SuppressLint({"SetJavaScriptEnabled"})
+ // Also, remove the warning about needing to override `performClick()` when using an `OnTouchListener` with `WebView`.
+ @SuppressLint({"SetJavaScriptEnabled", "ClickableViewAccessibility"})
// Remove Android Studio's warning about deprecations. We have to use the deprecated `getColor()` until API >= 23.
@SuppressWarnings("deprecation")
protected void onCreate(Bundle savedInstanceState) {
// Allow the downloading of files.
mainWebView.setDownloadListener((String url, String userAgent, String contentDisposition, String mimetype, long contentLength) -> {
- // Show the `DownloadFileDialog` `AlertDialog` and name this instance `@string/download`.
- AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength);
- downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ // Check to see if the WRITE_EXTERNAL_STORAGE permission has already been granted.
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
+ // The WRITE_EXTERNAL_STORAGE permission needs to be requested.
+
+ // Store the variables for future use by `onRequestPermissionsResult()`.
+ downloadUrl = url;
+ downloadContentDisposition = contentDisposition;
+ downloadContentLength = contentLength;
+
+ // Show a dialog if the user has previously denied the permission.
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
+ // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_FILE.
+ DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_FILE);
+
+ // Show the download location permission alert dialog. The permission will be requested when the the dialog is closed.
+ downloadLocationPermissionDialogFragment.show(getFragmentManager(), getString(R.string.download_location));
+ } else { // Show the permission request directly.
+ // Request the permission. The download dialog will be launched by `onRequestPermissionResult()`.
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_FILE_REQUEST_CODE);
+ }
+ } else { // The WRITE_EXTERNAL_STORAGE permission has already been granted.
+ // Get a handle for the download file alert dialog.
+ AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength);
+
+ // Show the download file alert dialog.
+ downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ }
});
// Allow pinch to zoom.
mainWebView.setWebViewClient(new WebViewClient() {
// `shouldOverrideUrlLoading` makes this `WebView` the default handler for URLs inside the app, so that links are not kicked out to other apps.
- // We have to use the deprecated `shouldOverrideUrlLoading` until API >= 24.
+ // The deprecated `shouldOverrideUrlLoading` must be used until API >= 24.
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (url.startsWith("mailto:")) { // Load the email address in an external email program.
+ if (url.startsWith("http")) { // Load the URL in Privacy Browser.
+ // Apply the domain settings for the new URL.
+ applyDomainSettings(url, true);
+
+ // Returning false causes the current `WebView` to handle the URL and prevents it from adding redirects to the history list.
+ return false;
+ } else if (url.startsWith("mailto:")) { // Load the email address in an external email program.
// Use `ACTION_SENDTO` instead of `ACTION_SEND` so that only email programs are launched.
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
- // Parse the url and set it as the data for the `Intent`.
+ // Parse the url and set it as the data for the intent.
emailIntent.setData(Uri.parse(url));
- // `FLAG_ACTIVITY_NEW_TASK` opens the email program in a new task instead as part of Privacy Browser.
+ // Open the email program in a new task instead of as part of Privacy Browser.
emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Make it so.
startActivity(emailIntent);
- // Returning `true` indicates the application is handling the URL.
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
return true;
} else if (url.startsWith("tel:")) { // Load the phone number in the dialer.
- // `ACTION_DIAL` open the dialer and loads the phone number, but waits for the user to place the call.
+ // Open the dialer and load the phone number, but wait for the user to place the call.
Intent dialIntent = new Intent(Intent.ACTION_DIAL);
// Add the phone number to the intent.
dialIntent.setData(Uri.parse(url));
- // `FLAG_ACTIVITY_NEW_TASK` opens the dialer in a new task instead as part of Privacy Browser.
+ // Open the dialer in a new task instead of as part of Privacy Browser.
dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Make it so.
startActivity(dialIntent);
- // Returning `true` indicates the application is handling the URL.
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
return true;
- } else { // Load the URL in Privacy Browser.
- // Apply the domain settings for the new URL.
- applyDomainSettings(url, true);
+ } else { // Load a system chooser to select an app that can handle the URL.
+ // Open an app that can handle the URL.
+ Intent genericIntent = new Intent(Intent.ACTION_VIEW);
- // Returning `false` causes the current `WebView` to handle the URL and prevents it from adding redirects to the history list.
- return false;
+ // Add the URL to the intent.
+ genericIntent.setData(Uri.parse(url));
+
+ // List all apps that can handle the URL instead of just opening the first one.
+ genericIntent.addCategory(Intent.CATEGORY_BROWSABLE);
+
+ // Open the app in a new task instead of as part of Privacy Browser.
+ genericIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Start the app or display a snackbar if no app is available to handle the URL.
+ try {
+ startActivity(genericIntent);
+ } catch (ActivityNotFoundException exception) {
+ Snackbar.make(mainWebView, getString(R.string.unrecognized_url) + " " + url, Snackbar.LENGTH_SHORT).show();
+ }
+
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
+ return true;
}
}
}
// Check Fanboy’s Annoyance List if it is enabled.
- if (fanboyAnnoyanceListEnabled) {
+ if (fanboysAnnoyanceListEnabled) {
if (blockListHelper.isBlocked(formattedUrlString, url, fanboyAnnoyance)) {
// The resource request was blocked. Return an empty web resource response.
return emptyWebResourceResponse;
}
- } else if (fanboySocialBlockingListEnabled){ // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled.
+ } else if (fanboysSocialBlockingListEnabled){ // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled.
if (blockListHelper.isBlocked(formattedUrlString, url, fanboySocial)) {
// The resource request was blocked. Return an empty web resource response.
return emptyWebResourceResponse;
// Manually delete cache folders.
try {
- // Delete the main `cache` folder.
+ // Delete the main cache directory.
privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache");
- // Delete the `app_webview` folder, which contains an additional `WebView` cache. See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`.
- privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview");
+ // Delete the secondary `Service Worker` cache directory.
+ // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise.
+ privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"});
} catch (IOException e) {
// Do nothing if an error is thrown.
}
drawerLayout.closeDrawer(GravityCompat.START);
}
+ // Close the bookmarks drawer if it is open.
+ if (drawerLayout.isDrawerVisible(GravityCompat.END)) {
+ drawerLayout.closeDrawer(GravityCompat.END);
+ }
+
// Clear the keyboard if displayed and remove the focus on the urlTextBar if it has it.
mainWebView.requestFocus();
}
// Run the default commands.
super.onRestart();
+ // Make sure Orbot is running if Privacy Browser is proxying through Orbot.
+ if (proxyThroughOrbot) {
+ // Request Orbot to start. If Orbot is already running no hard will be caused by this request.
+ Intent orbotIntent = new Intent("org.torproject.android.intent.action.START");
+
+ // Send the intent to the Orbot package.
+ orbotIntent.setPackage("org.torproject.android");
+
+ // Make it so.
+ sendBroadcast(orbotIntent);
+ }
+
// Apply the app settings if returning from the Settings activity..
- if (reapplyAppSettingsOnRestert) {
+ if (reapplyAppSettingsOnRestart) {
// Apply the app settings.
applyAppSettings();
}
// Reset the return from settings flag.
- reapplyAppSettingsOnRestert = false;
+ reapplyAppSettingsOnRestart = false;
}
// Apply the domain settings if returning from the Domains activity.
case R.id.settings:
// Set the flag to reapply app settings on restart when returning from Settings.
- reapplyAppSettingsOnRestert = true;
+ reapplyAppSettingsOnRestart = true;
// Set the flag to reapply the domain settings on restart when returning from Settings.
reapplyDomainSettingsOnRestart = true;
try {
// Delete the main cache directory.
privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache");
+
// Delete the secondary `Service Worker` cache directory.
- // We have to use a `String[]` because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise.
+ // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise.
privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"});
} catch (IOException e) {
// Do nothing if an error is thrown.
// Add a `Download Image` entry.
menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> {
- // Show the `DownloadImageDialog` `AlertDialog` and name this instance `@string/download`.
- AppCompatDialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(imageUrl);
- downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ // Check to see if the WRITE_EXTERNAL_STORAGE permission has already been granted.
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
+ // The WRITE_EXTERNAL_STORAGE permission needs to be requested.
+
+ // Store the image URL for use by `onRequestPermissionResult()`.
+ downloadImageUrl = imageUrl;
+
+ // Show a dialog if the user has previously denied the permission.
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
+ // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_IMAGE.
+ DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_IMAGE);
+
+ // Show the download location permission alert dialog. The permission will be requested when the dialog is closed.
+ downloadLocationPermissionDialogFragment.show(getFragmentManager(), getString(R.string.download_location));
+ } else { // Show the permission request directly.
+ // Request the permission. The download dialog will be launched by `onRequestPermissionResult().
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_IMAGE_REQUEST_CODE);
+ }
+ } else { // The WRITE_EXTERNAL_STORAGE permission has already been granted.
+ // Get a handle for the download image alert dialog.
+ AppCompatDialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(imageUrl);
+
+ // Show the download image alert dialog.
+ downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ }
return false;
});
// Add a `Download Image` entry.
menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> {
- // Show the `DownloadImageDialog` `AlertDialog` and name this instance `@string/download`.
- AppCompatDialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(imageUrl);
- downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ // Check to see if the WRITE_EXTERNAL_STORAGE permission has already been granted.
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
+ // The WRITE_EXTERNAL_STORAGE permission needs to be requested.
+
+ // Store the image URL for use by `onRequestPermissionResult()`.
+ downloadImageUrl = imageUrl;
+
+ // Show a dialog if the user has previously denied the permission.
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
+ // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_IMAGE.
+ DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_IMAGE);
+
+ // Show the download location permission alert dialog. The permission will be requested when the dialog is closed.
+ downloadLocationPermissionDialogFragment.show(getFragmentManager(), getString(R.string.download_location));
+ } else { // Show the permission request directly.
+ // Request the permission. The download dialog will be launched by `onRequestPermissionResult().
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_IMAGE_REQUEST_CODE);
+ }
+ } else { // The WRITE_EXTERNAL_STORAGE permission has already been granted.
+ // Get a handle for the download image alert dialog.
+ AppCompatDialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(imageUrl);
+
+ // Show the download image alert dialog.
+ downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ }
return false;
});
ShortcutManagerCompat.requestPinShortcut(this, shortcutInfoBuilder.build(), null);
}
+ @Override
+ public void onCloseDownloadLocationPermissionDialog(int downloadType) {
+ switch (downloadType) {
+ case DownloadLocationPermissionDialog.DOWNLOAD_FILE:
+ // Request the WRITE_EXTERNAL_STORAGE permission with a file request code.
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_FILE_REQUEST_CODE);
+ break;
+
+ case DownloadLocationPermissionDialog.DOWNLOAD_IMAGE:
+ // Request the WRITE_EXTERNAL_STORAGE permission with an image request code.
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_IMAGE_REQUEST_CODE);
+ break;
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case DOWNLOAD_FILE_REQUEST_CODE:
+ // Show the download file alert dialog. When the dialog closes, the correct command will be used based on the permission status.
+ AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(downloadUrl, downloadContentDisposition, downloadContentLength);
+
+ // On API 23, displaying the fragment must be delayed or the app will crash.
+ if (Build.VERSION.SDK_INT == 23) {
+ new Handler().postDelayed(() -> downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download)), 500);
+ } else {
+ downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ }
+
+ // Reset the download variables.
+ downloadUrl = "";
+ downloadContentDisposition = "";
+ downloadContentLength = 0;
+ break;
+
+ case DOWNLOAD_IMAGE_REQUEST_CODE:
+ // Show the download image alert dialog. When the dialog closes, the correct command will be used based on the permission status.
+ AppCompatDialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(downloadImageUrl);
+
+ // On API 23, displaying the fragment must be delayed or the app will crash.
+ if (Build.VERSION.SDK_INT == 23) {
+ new Handler().postDelayed(() -> downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download)), 500);
+ } else {
+ downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ }
+
+ // Reset the image URL variable.
+ downloadImageUrl = "";
+ break;
+ }
+ }
+
@Override
public void onDownloadImage(AppCompatDialogFragment dialogFragment, String imageUrl) {
// Download the image if it has an HTTP or HTTPS URI.
downloadRequest.addRequestHeader("Cookie", cookies);
}
- // Get the file name from `dialogFragment`.
+ // Get the file name from the dialog fragment.
EditText downloadImageNameEditText = dialogFragment.getDialog().findViewById(R.id.download_image_name);
String imageName = downloadImageNameEditText.getText().toString();
- // Once we have `WRITE_EXTERNAL_STORAGE` permissions we can use `setDestinationInExternalPublicDir`.
- if (Build.VERSION.SDK_INT >= 23) { // If API >= 23, set the download save in the the `DIRECTORY_DOWNLOADS` using `imageName`.
- downloadRequest.setDestinationInExternalFilesDir(this, "/", imageName);
- } else { // Only set the title using `imageName`.
- downloadRequest.setTitle(imageName);
+ // Specify the download location.
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // External write permission granted.
+ // Download to the public download directory.
+ downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, imageName);
+ } else { // External write permission denied.
+ // Download to the app's external download directory.
+ downloadRequest.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, imageName);
}
// Allow `MediaScanner` to index the download if it is a media file.
public void onDownloadFile(AppCompatDialogFragment dialogFragment, String downloadUrl) {
// Download the file if it has an HTTP or HTTPS URI.
if (downloadUrl.startsWith("http")) {
-
// Get a handle for the system `DOWNLOAD_SERVICE`.
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
downloadRequest.addRequestHeader("Cookie", cookies);
}
- // Get the file name from `dialogFragment`.
+ // Get the file name from the dialog fragment.
EditText downloadFileNameEditText = dialogFragment.getDialog().findViewById(R.id.download_file_name);
String fileName = downloadFileNameEditText.getText().toString();
- // Once we have `WRITE_EXTERNAL_STORAGE` permissions we can use `setDestinationInExternalPublicDir`.
- if (Build.VERSION.SDK_INT >= 23) { // If API >= 23, set the download location to `/sdcard/Android/data/com.stoutner.privacybrowser.standard/files` named `fileName`.
- downloadRequest.setDestinationInExternalFilesDir(this, "/", fileName);
- } else { // Only set the title using `fileName`.
- downloadRequest.setTitle(fileName);
+ // Specify the download location.
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // External write permission granted.
+ // Download to the public download directory.
+ downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
+ } else { // External write permission denied.
+ // Download to the app's external download directory.
+ downloadRequest.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, fileName);
}
// Allow `MediaScanner` to index the download if it is a media file.
String torSearchCustomURLString = sharedPreferences.getString("tor_search_custom_url", "");
String searchString = sharedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
String searchCustomURLString = sharedPreferences.getString("search_custom_url", "");
- easyListEnabled = sharedPreferences.getBoolean("easylist", true);
- easyPrivacyEnabled = sharedPreferences.getBoolean("easyprivacy", true);
- fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboy_annoyance_list", true);
- fanboySocialBlockingListEnabled = sharedPreferences.getBoolean("fanboy_social_blocking_list", true);
incognitoModeEnabled = sharedPreferences.getBoolean("incognito_mode", false);
boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", false);
- boolean proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
+ proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
hideSystemBarsOnFullscreen = sharedPreferences.getBoolean("hide_system_bars", false);
translucentNavigationBarOnFullscreen = sharedPreferences.getBoolean("translucent_navigation_bar", true);
thirdPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1);
domStorageEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1);
saveFormDataEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1);
+ easyListEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST)) == 1);
+ easyPrivacyEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY)) == 1);
+ fanboysAnnoyanceListEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1);
+ fanboysSocialBlockingListEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)) == 1);
String userAgentString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
int fontSize = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
displayWebpageImagesInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
thirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies_enabled", false);
domStorageEnabled = sharedPreferences.getBoolean("dom_storage_enabled", false);
saveFormDataEnabled = sharedPreferences.getBoolean("save_form_data_enabled", false);
+ easyListEnabled = sharedPreferences.getBoolean("easylist", true);
+ easyPrivacyEnabled = sharedPreferences.getBoolean("easyprivacy", true);
+ fanboysAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboy_annoyance_list", true);
+ fanboysSocialBlockingListEnabled = sharedPreferences.getBoolean("fanboy_social_blocking_list", true);
// Set `javaScriptEnabled` to be `true` if `night_mode` is `true`.
if (nightMode) {
bookmarksTitleTextView.setText(currentBookmarksFolder);
}
}
-}
+}
\ No newline at end of file