import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.DialogFragment;
-import androidx.fragment.app.FragmentManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager.widget.ViewPager;
import com.stoutner.privacybrowser.dialogs.CreateBookmarkDialog;
import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog;
import com.stoutner.privacybrowser.dialogs.CreateHomeScreenShortcutDialog;
-import com.stoutner.privacybrowser.dialogs.DownloadFileDialog;
-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.FontSizeDialog;
import com.stoutner.privacybrowser.dialogs.OpenDialog;
import com.stoutner.privacybrowser.dialogs.ProxyNotInstalledDialog;
import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog;
-import com.stoutner.privacybrowser.dialogs.SaveWebpageDialog;
+import com.stoutner.privacybrowser.dialogs.SaveDialog;
import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog;
import com.stoutner.privacybrowser.dialogs.StoragePermissionDialog;
import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog;
import java.util.Objects;
import java.util.Set;
-// 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, FontSizeDialog.UpdateFontSizeListener, NavigationView.OnNavigationItemSelectedListener, OpenDialog.OpenListener,
- PinnedMismatchDialog.PinnedMismatchListener, PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageDialog.SaveWebpageListener, StoragePermissionDialog.StoragePermissionDialogListener,
- UrlHistoryDialog.NavigateHistoryListener, WebViewTabFragment.NewTabListener {
+ EditBookmarkDialog.EditBookmarkListener, EditBookmarkFolderDialog.EditBookmarkFolderListener, FontSizeDialog.UpdateFontSizeListener, NavigationView.OnNavigationItemSelectedListener,
+ OpenDialog.OpenListener, PinnedMismatchDialog.PinnedMismatchListener, PopulateBlocklists.PopulateBlocklistsListener, SaveDialog.SaveWebpageListener,
+ StoragePermissionDialog.StoragePermissionDialogListener, UrlHistoryDialog.NavigateHistoryListener, WebViewTabFragment.NewTabListener {
// `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxy()`.
public static String orbotStatus = "unknown";
public static String proxyMode = ProxyHelper.NONE;
- // The permission result request codes are used in `onCreateContextMenu()`, `onCloseDownloadLocationPermissionDialog()`, `onRequestPermissionResult()`, `onSaveWebpage()`,
- // `onCloseStoragePermissionDialog()`, and `initializeWebView()`.
- private final int PERMISSION_DOWNLOAD_FILE_REQUEST_CODE = 0;
- private final int PERMISSION_DOWNLOAD_IMAGE_REQUEST_CODE = 1;
- private final int PERMISSION_OPEN_REQUEST_CODE = 2;
- private final int PERMISSION_SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE = 3;
- private final int PERMISSION_SAVE_WEBPAGE_IMAGE_REQUEST_CODE = 4;
- private final int PERMISSION_SAVE_WEBPAGE_RAW_REQUEST_CODE = 5;
+ // The permission result request codes are used in `onCreateContextMenu()`, `onRequestPermissionResult()`, `onSaveWebpage()`, `onCloseStoragePermissionDialog()`, and `initializeWebView()`.
+ private final int PERMISSION_OPEN_REQUEST_CODE = 0;
+ private final int PERMISSION_SAVE_URL_REQUEST_CODE = 1;
+ private final int PERMISSION_SAVE_AS_ARCHIVE_REQUEST_CODE = 2;
+ private final int PERMISSION_SAVE_AS_IMAGE_REQUEST_CODE = 3;
// The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`,
// `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxy()`, and `applyDomainSettings()`.
private boolean sanitizeFacebookClickIds;
private boolean sanitizeTwitterAmpRedirects;
- // The download strings are used in `onCreate()`, `onRequestPermissionResult()` and `initializeWebView()`.
- private String downloadUrl;
- private String downloadContentDisposition;
- private long downloadContentLength;
-
- // `downloadImageUrl` is used in `onCreateContextMenu()` and `onRequestPermissionResult()`.
- private String downloadImageUrl;
-
- // The file path strings are used in `onSaveWebpageImage()` and `onRequestPermissionResult()`
+ // The file path strings are used in `onSaveWebpage()` and `onRequestPermissionResult()`
private String openFilePath;
private String saveWebpageUrl;
private String saveWebpageFilePath;
// Remove the warning about needing to override `performClick()` when using an `OnTouchListener` with `WebView`.
@SuppressLint("ClickableViewAccessibility")
protected void onCreate(Bundle savedInstanceState) {
+ // Enable the drawing of the entire webpage. This makes it possible to save a website image. This must be done before anything else happens with the WebView.
if (Build.VERSION.SDK_INT >= 21) {
WebView.enableSlowWholeDocumentDraw();
}
// Consume the event.
return true;
- case R.id.add_or_edit_domain:
- if (currentWebView.getDomainSettingsApplied()) { // Edit the current domain settings.
- // Reapply the domain settings on returning to `MainWebViewActivity`.
- reapplyDomainSettingsOnRestart = true;
-
- // Create an intent to launch the domains activity.
- Intent domainsIntent = new Intent(this, DomainsActivity.class);
-
- // Add the extra information to the intent.
- domainsIntent.putExtra("load_domain", currentWebView.getDomainSettingsDatabaseId());
- 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.
- // Apply the new domain settings on returning to `MainWebViewActivity`.
- reapplyDomainSettingsOnRestart = true;
-
- // Get the current domain
- Uri currentUri = Uri.parse(currentWebView.getUrl());
- String currentDomain = currentUri.getHost();
-
- // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
- DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(this, null, null, 0);
-
- // Create the domain and store the database ID.
- int newDomainDatabaseId = domainsDatabaseHelper.addDomain(currentDomain);
-
- // Create an intent to launch the domains activity.
- Intent domainsIntent = new Intent(this, DomainsActivity.class);
-
- // Add the extra information to the intent.
- domainsIntent.putExtra("load_domain", newDomainDatabaseId);
- 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();
+ case R.id.refresh:
+ if (menuItem.getTitle().equals(getString(R.string.refresh))) { // The refresh button was pushed.
+ // Reload the current WebView.
+ currentWebView.reload();
+ } else { // The stop button was pushed.
+ // Stop the loading of the WebView.
+ currentWebView.stopLoading();
+ }
- // 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);
- }
+ // Consume the event.
+ return true;
- // 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());
- }
+ case R.id.bookmarks:
+ // Get a handle for the drawer layout.
+ DrawerLayout drawerLayout = findViewById(R.id.drawerlayout);
- // Make it so.
- startActivity(domainsIntent);
- }
+ // Open the bookmarks drawer.
+ drawerLayout.openDrawer(GravityCompat.END);
// Consume the event.
return true;
case R.id.save_url:
// Instantiate the save dialog.
- DialogFragment saveDialogFragment = SaveWebpageDialog.saveUrl(StoragePermissionDialog.SAVE, currentWebView.getCurrentUrl());
+ DialogFragment saveDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_URL, currentWebView.getCurrentUrl(), currentWebView.getSettings().getUserAgentString(),
+ currentWebView.getAcceptFirstPartyCookies());
// Show the save dialog. It must be named `save_dialog` so that the file picked can update the file name.
saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
case R.id.save_as_archive:
// Instantiate the save webpage archive dialog.
- DialogFragment saveWebpageArchiveDialogFragment = SaveWebpageDialog.saveUrl(StoragePermissionDialog.SAVE_AS_ARCHIVE, currentWebView.getCurrentUrl());
+ DialogFragment saveWebpageArchiveDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_AS_ARCHIVE, currentWebView.getCurrentUrl(), currentWebView.getSettings().getUserAgentString(),
+ currentWebView.getAcceptFirstPartyCookies());
// Show the save webpage archive dialog. It must be named `save_dialog` so that the file picked can update the file name.
saveWebpageArchiveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
case R.id.save_as_image:
// Instantiate the save webpage image dialog. It must be named `save_webpage` so that the file picked can update the file name.
- DialogFragment saveWebpageImageDialogFragment = SaveWebpageDialog.saveUrl(StoragePermissionDialog.SAVE_AS_IMAGE, currentWebView.getCurrentUrl());
+ DialogFragment saveWebpageImageDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_AS_IMAGE, currentWebView.getCurrentUrl(), currentWebView.getSettings().getUserAgentString(),
+ currentWebView.getAcceptFirstPartyCookies());
// Show the save webpage image dialog. It must be named `save_dialog` so that the file picked can update the file name.
saveWebpageImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
// Consume the event.
return true;
- case R.id.refresh:
- if (menuItem.getTitle().equals(getString(R.string.refresh))) { // The refresh button was pushed.
- // Reload the current WebView.
- currentWebView.reload();
- } else { // The stop button was pushed.
- // Stop the loading of the WebView.
- currentWebView.stopLoading();
+ case R.id.add_or_edit_domain:
+ if (currentWebView.getDomainSettingsApplied()) { // Edit the current domain settings.
+ // Reapply the domain settings on returning to `MainWebViewActivity`.
+ reapplyDomainSettingsOnRestart = true;
+
+ // Create an intent to launch the domains activity.
+ Intent domainsIntent = new Intent(this, DomainsActivity.class);
+
+ // Add the extra information to the intent.
+ domainsIntent.putExtra("load_domain", currentWebView.getDomainSettingsDatabaseId());
+ 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.
+ // Apply the new domain settings on returning to `MainWebViewActivity`.
+ reapplyDomainSettingsOnRestart = true;
+
+ // Get the current domain
+ Uri currentUri = Uri.parse(currentWebView.getUrl());
+ String currentDomain = currentUri.getHost();
+
+ // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
+ DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(this, null, null, 0);
+
+ // Create the domain and store the database ID.
+ int newDomainDatabaseId = domainsDatabaseHelper.addDomain(currentDomain);
+
+ // Create an intent to launch the domains activity.
+ Intent domainsIntent = new Intent(this, DomainsActivity.class);
+
+ // Add the extra information to the intent.
+ domainsIntent.putExtra("load_domain", newDomainDatabaseId);
+ 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);
}
// Consume the event.
// Launch as a new task so that Download Manager and Privacy Browser show as separate windows in the recent tasks list.
downloadManagerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // Make it so.
startActivity(downloadManagerIntent);
break;
// Add a Save URL entry.
menu.add(R.string.save_url).setOnMenuItemClickListener((MenuItem item) -> {
// Instantiate the save dialog.
- DialogFragment saveDialogFragment = SaveWebpageDialog.saveUrl(StoragePermissionDialog.SAVE, linkUrl);
+ DialogFragment saveDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_URL, linkUrl, currentWebView.getSettings().getUserAgentString(),
+ currentWebView.getAcceptFirstPartyCookies());
- // Show the save dialog. It must be named `save_dialog` so that the file picked can update the file name.
+ // Show the save dialog. It must be named `save_dialog` so that the file picker can update the file name.
saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
// Consume the event.
// Add a Save Image entry.
menu.add(R.string.save_image).setOnMenuItemClickListener((MenuItem item) -> {
// Instantiate the save dialog.
- DialogFragment saveDialogFragment = SaveWebpageDialog.saveUrl(StoragePermissionDialog.SAVE, imageUrl);
+ DialogFragment saveDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_URL, imageUrl, currentWebView.getSettings().getUserAgentString(),
+ currentWebView.getAcceptFirstPartyCookies());
// Show the save dialog. It must be named `save_dialog` so that the file picked can update the file name.
saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
menu.add(R.string.save_image).setOnMenuItemClickListener((MenuItem item) -> {
// Instantiate the save dialog.
- DialogFragment saveDialogFragment = SaveWebpageDialog.saveUrl(StoragePermissionDialog.SAVE, imageUrl);
+ DialogFragment saveDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_URL, imageUrl, currentWebView.getSettings().getUserAgentString(),
+ currentWebView.getAcceptFirstPartyCookies());
// Show the save raw dialog. It must be named `save_dialog` so that the file picked can update the file name.
saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
menu.add(R.string.save_url).setOnMenuItemClickListener((MenuItem item) -> {
// Instantiate the save dialog.
- DialogFragment saveDialogFragment = SaveWebpageDialog.saveUrl(StoragePermissionDialog.SAVE, linkUrl);
+ DialogFragment saveDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_URL, linkUrl, currentWebView.getSettings().getUserAgentString(),
+ currentWebView.getAcceptFirstPartyCookies());
// Show the save raw dialog. It must be named `save_dialog` so that the file picked can update the file name.
saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
bookmarksCursorAdapter.changeCursor(bookmarksCursor);
}
- @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}, PERMISSION_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}, PERMISSION_DOWNLOAD_IMAGE_REQUEST_CODE);
- break;
- }
- }
-
- @Override
- public void onDownloadImage(DialogFragment dialogFragment, String imageUrl) {
- // Download the image if it has an HTTP or HTTPS URI.
- if (imageUrl.startsWith("http")) {
- // Get a handle for the system `DOWNLOAD_SERVICE`.
- DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
-
- // 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 (cookieManager.acceptCookie()) {
- // Get the cookies for `imageUrl`.
- String cookies = cookieManager.getCookie(imageUrl);
-
- // Add the cookies to `downloadRequest`. In the HTTP request header, cookies are named `Cookie`.
- downloadRequest.addRequestHeader("Cookie", cookies);
- }
-
- // Get the dialog.
- Dialog dialog = dialogFragment.getDialog();
-
- // Remove the incorrect lint warning below that the dialog might be null.
- assert dialog != null;
-
- // Get the file name from the dialog fragment.
- EditText downloadImageNameEditText = dialog.findViewById(R.id.download_image_name);
- String imageName = downloadImageNameEditText.getText().toString();
-
- // 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.
- downloadRequest.allowScanningByMediaScanner();
-
- // Add the URL as the description for the download.
- downloadRequest.setDescription(imageUrl);
-
- // Show the download notification after the download is completed.
- downloadRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
-
- // Remove the lint warning below that `downloadManager` might be `null`.
- assert downloadManager != null;
-
- // Initiate the download.
- downloadManager.enqueue(downloadRequest);
- } else { // The image is not an HTTP or HTTPS URI.
- Snackbar.make(currentWebView, R.string.cannot_download_image, Snackbar.LENGTH_INDEFINITE).show();
- }
- }
-
- @Override
- public void onDownloadFile(DialogFragment 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);
-
- // 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 (cookieManager.acceptCookie()) {
- // Get the cookies for `downloadUrl`.
- String cookies = cookieManager.getCookie(downloadUrl);
-
- // Add the cookies to `downloadRequest`. In the HTTP request header, cookies are named `Cookie`.
- downloadRequest.addRequestHeader("Cookie", cookies);
- }
-
- // Get the dialog.
- Dialog dialog = dialogFragment.getDialog();
-
- // Remove the incorrect lint warning below that the dialog might be null.
- assert dialog != null;
-
- // Get the file name from the dialog.
- EditText downloadFileNameEditText = dialog.findViewById(R.id.download_file_name);
- String fileName = downloadFileNameEditText.getText().toString();
-
- // 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.
- downloadRequest.allowScanningByMediaScanner();
-
- // Add the URL as the description for the download.
- downloadRequest.setDescription(downloadUrl);
-
- // Show the download notification after the download is completed.
- downloadRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
-
- // Remove the lint warning below that `downloadManager` might be `null`.
- assert downloadManager != null;
-
- // Initiate the download.
- downloadManager.enqueue(downloadRequest);
- } else { // The download is not an HTTP or HTTPS URI.
- Snackbar.make(currentWebView, R.string.cannot_download_file, Snackbar.LENGTH_INDEFINITE).show();
- }
- }
-
// Override `onBackPressed` to handle the navigation drawer and and the WebViews.
@Override
public void onBackPressed() {
// Get the font size from the edit text.
try {
- newFontSize = Integer.valueOf(fontSizeEditText.getText().toString());
+ newFontSize = Integer.parseInt(fontSizeEditText.getText().toString());
} catch (Exception exception) {
// If the edit text does not contain a valid font size do nothing.
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted.
//Save the webpage according to the save type.
switch (saveType) {
- case StoragePermissionDialog.SAVE:
+ case StoragePermissionDialog.SAVE_URL:
// Save the URL.
new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
break;
if (saveWebpageFilePath.startsWith(externalPrivateDirectory)) { // The file path is in the external private directory.
// Save the webpage according to the save type.
switch (saveType) {
- case StoragePermissionDialog.SAVE:
+ case StoragePermissionDialog.SAVE_URL:
// Save the URL.
new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
break;
storagePermissionDialogFragment.show(getSupportFragmentManager(), getString(R.string.storage_permission));
} else { // Show the permission request directly.
switch (saveType) {
- case StoragePermissionDialog.SAVE:
+ case StoragePermissionDialog.SAVE_URL:
// Request the write external storage permission. The URL will be saved when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_WEBPAGE_RAW_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_URL_REQUEST_CODE);
case StoragePermissionDialog.SAVE_AS_ARCHIVE:
// Request the write external storage permission. The webpage archive will be saved when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_AS_ARCHIVE_REQUEST_CODE);
break;
case StoragePermissionDialog.SAVE_AS_IMAGE:
// Request the write external storage permission. The webpage image will be saved when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_WEBPAGE_IMAGE_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_AS_IMAGE_REQUEST_CODE);
break;
}
}
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_OPEN_REQUEST_CODE);
break;
- case StoragePermissionDialog.SAVE:
+ case StoragePermissionDialog.SAVE_URL:
// Request the write external storage permission. The URL will be saved when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_WEBPAGE_RAW_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_URL_REQUEST_CODE);
break;
case StoragePermissionDialog.SAVE_AS_ARCHIVE:
// Request the write external storage permission. The webpage archive will be saved when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_AS_ARCHIVE_REQUEST_CODE);
break;
case StoragePermissionDialog.SAVE_AS_IMAGE:
// Request the write external storage permission. The webpage image will be saved when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_WEBPAGE_IMAGE_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_SAVE_AS_IMAGE_REQUEST_CODE);
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- // Get a handle for the fragment manager.
- FragmentManager fragmentManager = getSupportFragmentManager();
-
- switch (requestCode) {
- case PERMISSION_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.
- DialogFragment 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(fragmentManager, getString(R.string.download)), 500);
- } else {
- downloadFileDialogFragment.show(fragmentManager, getString(R.string.download));
- }
-
- // Reset the download variables.
- downloadUrl = "";
- downloadContentDisposition = "";
- downloadContentLength = 0;
- break;
-
- case PERMISSION_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.
- DialogFragment 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(fragmentManager, getString(R.string.download)), 500);
- } else {
- downloadImageDialogFragment.show(fragmentManager, getString(R.string.download));
- }
-
- // Reset the image URL variable.
- downloadImageUrl = "";
- break;
-
- case PERMISSION_OPEN_REQUEST_CODE:
- // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
- if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // The storage permission was granted.
- // Load the file.
- currentWebView.loadUrl("file://" + openFilePath);
- } else { // The storage permission was not granted.
- // Display an error snackbar.
- Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
- }
+ //Only process the results if they exist (this method is triggered when a dialog is presented the first time for an app, but no grant results are included).
+ if (grantResults.length > 0) {
+ switch (requestCode) {
+ case PERMISSION_OPEN_REQUEST_CODE:
+ // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // The storage permission was granted.
+ // Load the file.
+ currentWebView.loadUrl("file://" + openFilePath);
+ } else { // The storage permission was not granted.
+ // Display an error snackbar.
+ Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
+ }
- // Reset the open file path.
- openFilePath = "";
- break;
+ // Reset the open file path.
+ openFilePath = "";
+ break;
- case PERMISSION_SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE:
- // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
- if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // The storage permission was granted.
- // Save the webpage archive.
- currentWebView.saveWebArchive(saveWebpageFilePath);
- } else { // The storage permission was not granted.
- // Display an error snackbar.
- Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
- }
+ case PERMISSION_SAVE_URL_REQUEST_CODE:
+ // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // The storage permission was granted.
+ // Save the raw URL.
+ new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
+ } else { // The storage permission was not granted.
+ // Display an error snackbar.
+ Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
+ }
- // Reset the save webpage file path.
- saveWebpageFilePath = "";
- break;
+ // Reset the save strings.
+ saveWebpageUrl = "";
+ saveWebpageFilePath = "";
+ break;
- case PERMISSION_SAVE_WEBPAGE_IMAGE_REQUEST_CODE:
- // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
- if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // The storage permission was granted.
- // Save the webpage image.
- new SaveWebpageImage(this, currentWebView).execute(saveWebpageFilePath);
- } else { // The storage permission was not granted.
- // Display an error snackbar.
- Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
- }
+ case PERMISSION_SAVE_AS_ARCHIVE_REQUEST_CODE:
+ // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // The storage permission was granted.
+ // Save the webpage archive.
+ currentWebView.saveWebArchive(saveWebpageFilePath);
+ } else { // The storage permission was not granted.
+ // Display an error snackbar.
+ Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
+ }
- // Reset the save webpage file path.
- saveWebpageFilePath = "";
- break;
+ // Reset the save webpage file path.
+ saveWebpageFilePath = "";
+ break;
- case PERMISSION_SAVE_WEBPAGE_RAW_REQUEST_CODE:
- // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
- if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // The storage permission was granted.
- // Save the raw URL.
- new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
- } else { // The storage permission was not granted.
- // Display an error snackbar.
- Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
- }
+ case PERMISSION_SAVE_AS_IMAGE_REQUEST_CODE:
+ // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // The storage permission was granted.
+ // Save the webpage image.
+ new SaveWebpageImage(this, currentWebView).execute(saveWebpageFilePath);
+ } else { // The storage permission was not granted.
+ // Display an error snackbar.
+ Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
+ }
- // Reset the save strings.
- saveWebpageUrl = "";
- saveWebpageFilePath = "";
- break;
+ // Reset the save webpage file path.
+ saveWebpageFilePath = "";
+ break;
+ }
}
}
try { // Try the specified font size to see if it is valid.
if (fontSize == 0) { // Apply the default font size.
// Try to set the font size from the value in the app settings.
- nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
+ nestedScrollWebView.getSettings().setTextZoom(Integer.parseInt(defaultFontSizeString));
} else { // Apply the font size from domain settings.
nestedScrollWebView.getSettings().setTextZoom(fontSize);
}
// Apply the default font size setting.
try {
// Try to set the font size from the value in the app settings.
- nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
+ nestedScrollWebView.getSettings().setTextZoom(Integer.parseInt(defaultFontSizeString));
} catch (Exception exception) {
// If the app settings value is invalid, set the font size to 100%.
nestedScrollWebView.getSettings().setTextZoom(100);
}
private void openWithApp(String url) {
- // Create the open with intent with `ACTION_VIEW`.
+ // Create an open with app intent with `ACTION_VIEW`.
Intent openWithAppIntent = new Intent(Intent.ACTION_VIEW);
// Set the URI but not the MIME type. This should open all available apps.
// Flag the intent to open in a new task.
openWithAppIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // Try the intent.
try {
// Show the chooser.
startActivity(openWithAppIntent);
- } catch (ActivityNotFoundException exception) {
+ } catch (ActivityNotFoundException exception) { // There are no apps available to open the URL.
// Show a snackbar with the error.
Snackbar.make(currentWebView, getString(R.string.error) + " " + exception, Snackbar.LENGTH_INDEFINITE).show();
}
}
private void openWithBrowser(String url) {
- // Create the open with intent with `ACTION_VIEW`.
+ // Create an open with browser intent with `ACTION_VIEW`.
Intent openWithBrowserIntent = new Intent(Intent.ACTION_VIEW);
// Set the URI and the MIME type. `"text/html"` should load browser options.
// Flag the intent to open in a new task.
openWithBrowserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // Try the intent.
try {
// Show the chooser.
startActivity(openWithBrowserIntent);
- } catch (ActivityNotFoundException exception) {
+ } catch (ActivityNotFoundException exception) { // There are no browsers available to open the URL.
// Show a snackbar with the error.
Snackbar.make(currentWebView, getString(R.string.error) + " " + exception, Snackbar.LENGTH_INDEFINITE).show();
}
// Allow the downloading of files.
nestedScrollWebView.setDownloadListener((String downloadUrl, String userAgent, String contentDisposition, String mimetype, long contentLength) -> {
- // Check if the download should be processed by an external app.
- if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app.
- // 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. Specifying `text/html` displays a good number of options.
- downloadIntent.setDataAndType(Uri.parse(downloadUrl), "text/html");
-
- // Flag the intent to open in a new task.
- downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- // Show the chooser.
- startActivity(Intent.createChooser(downloadIntent, getString(R.string.open_with)));
- } else { // Download with Android's download manager.
- // 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 storage permission has not been granted.
- // The WRITE_EXTERNAL_STORAGE permission needs to be requested.
-
- // Store the variables for future use by `onRequestPermissionsResult()`.
- this.downloadUrl = downloadUrl;
- 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.
- // Instantiate the download location permission alert dialog and set the download type to DOWNLOAD_FILE.
- DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_FILE);
-
- // Show the download location permission alert dialog. The permission will be requested when the the dialog is closed.
- downloadLocationPermissionDialogFragment.show(getSupportFragmentManager(), 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}, PERMISSION_DOWNLOAD_FILE_REQUEST_CODE);
- }
- } else { // The storage permission has already been granted.
- // Get a handle for the download file alert dialog.
- DialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(downloadUrl, contentDisposition, contentLength);
+ // Instantiate the save dialog.
+ DialogFragment saveDialogFragment = SaveDialog.saveUrl(StoragePermissionDialog.SAVE_URL, downloadUrl, userAgent, nestedScrollWebView.getAcceptFirstPartyCookies());
- // Show the download file alert dialog.
- downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
- }
- }
+ // Show the save dialog. It must be named `save_dialog` so that the file picker can update the file name.
+ saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
});
// Update the find on page count.