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.SaveWebpageImageDialog;
import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog;
import com.stoutner.privacybrowser.dialogs.StoragePermissionDialog;
// 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, NavigationView.OnNavigationItemSelectedListener, PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageImageDialog.SaveWebpageImageListener,
- StoragePermissionDialog.StoragePermissionDialogListener, WebViewTabFragment.NewTabListener {
+ EditBookmarkFolderDialog.EditBookmarkFolderListener, NavigationView.OnNavigationItemSelectedListener, PinnedMismatchDialog.PinnedMismatchListener, PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageImageDialog.SaveWebpageImageListener,
+ 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 `applyProxyThroughOrbot()`.
public static String orbotStatus;
case R.id.back:
if (currentWebView.canGoBack()) {
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the previous entry URL.
+ String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl();
+
// Reset the current domain name so that navigation works if third-party requests are blocked.
currentWebView.resetCurrentDomainName();
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, previousUrl, false, false);
// Load the previous website in the history.
currentWebView.goBack();
case R.id.forward:
if (currentWebView.canGoForward()) {
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the next entry URL.
+ String nextUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() + 1).getUrl();
+
// Reset the current domain name so that navigation works if third-party requests are blocked.
currentWebView.resetCurrentDomainName();
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, nextUrl, false, false);
// Load the next website in the history.
currentWebView.goForward();
}
}
- // Override `onBackPressed` to handle the navigation drawer and and the WebView.
+ // Override `onBackPressed` to handle the navigation drawer and and the WebViews.
@Override
public void onBackPressed() {
// Get a handle for the drawer layout and the tab layout.
loadBookmarksFolder();
}
} else if (currentWebView.canGoBack()) { // There is at least one item in the current WebView history.
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the previous entry URL.
+ String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl();
+
// Reset the current domain name so that navigation works if third-party requests are blocked.
currentWebView.resetCurrentDomainName();
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, previousUrl, false, false);
// Go back.
currentWebView.goBack();
bareWebView.destroy();
}
+ @Override
+ public void navigateHistory(String url, int steps) {
+ // Reset the current domain name so that navigation works if third-party requests are blocked.
+ currentWebView.resetCurrentDomainName();
+
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, url, false, false);
+
+ // Load the history entry.
+ currentWebView.goBackOrForward(steps);
+ }
+
+ @Override
+ public void pinnedErrorGoBack() {
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the previous entry URL.
+ String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl();
+
+ // Reset the current domain name so that navigation works if third-party requests are blocked.
+ currentWebView.resetCurrentDomainName();
+
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, previousUrl, false, false);
+
+ // Go back.
+ currentWebView.goBack();
+ }
+
// `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 resetTab, boolean reloadWebsite) {
// Get the IP addresses for the host.
new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost());
- // Apply any custom domain settings if the URL was loaded by navigating history.
- if (nestedScrollWebView.getNavigatingHistory()) {
- // Reset navigating history.
- nestedScrollWebView.setNavigatingHistory(false);
-
- // Apply the domain settings.
- boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, 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);
- }
- }
-
// Replace Refresh with Stop if the options menu has been created. (The first WebView typically begins loading before the menu items are instantiated.)
if (optionsMenu != null) {
// Get a handle for the refresh menu item.
import androidx.viewpager.widget.PagerAdapter;
public class PinnedMismatchDialog extends DialogFragment {
+ // The public interface is used to send information back to the parent activity.
+ public interface PinnedMismatchListener {
+ void pinnedErrorGoBack();
+ }
+
// Declare the class variables.
+ private PinnedMismatchListener pinnedMismatchListener;
private NestedScrollWebView nestedScrollWebView;
private String currentSslIssuedToCName;
private String currentSslIssuedToOName;
private Date currentSslStartDate;
private Date currentSslEndDate;
+ @Override
+ public void onAttach(Context context) {
+ // Run the default commands.
+ super.onAttach(context);
+
+ // Get a handle for the listener from the launching context.
+ pinnedMismatchListener = (PinnedMismatchListener) context;
+ }
+
public static PinnedMismatchDialog displayDialog(long webViewFragmentId) {
// Create an arguments bundle.
Bundle argumentsBundle = new Bundle();
// Setup the back button.
dialogBuilder.setNegativeButton(R.string.back, (DialogInterface dialog, int which) -> {
if (nestedScrollWebView.canGoBack()) { // There is a back page in the history.
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- nestedScrollWebView.resetCurrentDomainName();
-
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- nestedScrollWebView.setNavigatingHistory(true);
-
- // Go back.
- nestedScrollWebView.goBack();
+ // Invoke the navigate history listener in the calling activity. These commands cannot be run here because they need access to `applyDomainSettings()`.
+ pinnedMismatchListener.pinnedErrorGoBack();
} else { // There are no pages to go back to.
// Load a blank page
nestedScrollWebView.loadUrl("");
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.webkit.WebBackForwardList;
import android.widget.AdapterView;
import android.widget.ListView;
+import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
public class UrlHistoryDialog extends DialogFragment{
+ // The public interface is used to send information back to the parent activity.
+ public interface NavigateHistoryListener {
+ void navigateHistory(String url, int steps);
+ }
+
+ // The navigate history listener is used in `onAttach()` and `onCreateDialog()`.
+ private NavigateHistoryListener navigateHistoryListener;
+
+ @Override
+ public void onAttach(Context context) {
+ // Run the default commands.
+ super.onAttach(context);
+
+ // Get a handle for the listener from the launching context.
+ navigateHistoryListener = (NavigateHistoryListener) context;
+ }
+
public static UrlHistoryDialog loadBackForwardList(long webViewFragmentId) {
// Create an arguments bundle.
Bundle argumentsBundle = new Bundle();
// Create a history array list.
ArrayList<History> historyArrayList = new ArrayList<>();
- // Populate the history array list, descending from `urlStringArrayList.size()` so that the newest entries are at the top. `-1` is needed because the history array list is zero-based.
+ // Populate the history array list, descending from the end of the list so that the newest entries are at the top. `-1` is needed because the history array list is zero-based.
for (int i=webBackForwardList.getSize() -1; i >= 0; i--) {
// Create a variable to store the favorite icon bitmap.
Bitmap favoriteIconBitmap;
// Only consume the click if it is not on the `currentPageId`.
if (itemId != currentPageId) {
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- nestedScrollWebView.resetCurrentDomainName();
+ // Get a handle for the URL text view.
+ TextView urlTextView = view.findViewById(R.id.history_url_textview);
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- nestedScrollWebView.setNavigatingHistory(true);
+ // Get the URL.
+ String url = urlTextView.getText().toString();
- // Load the history entry.
- nestedScrollWebView.goBackOrForward(currentPageId - itemId);
+ // Invoke the navigate history listener in the calling activity. These commands cannot be run here because they need access to `applyDomainSettings()`.
+ navigateHistoryListener.navigateHistory(url, currentPageId - itemId);
// Dismiss the alert dialog.
alertDialog.dismiss();