From 0cc9b798d6daa99959e33ff94a707516d6db8122 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 20 Mar 2019 15:59:52 -0700 Subject: [PATCH] Update the URL edit text when switching tabs. --- .../activities/MainWebViewActivity.java | 257 +++++++----------- .../asynctasks/GetHostIpAddresses.java | 122 +++++++++ .../dialogs/PinnedMismatchDialog.java | 16 +- .../views/NestedScrollWebView.java | 24 ++ 4 files changed, 253 insertions(+), 166 deletions(-) create mode 100644 app/src/main/java/com/stoutner/privacybrowser/asynctasks/GetHostIpAddresses.java diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index 1ec5a020..041b6d2a 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -46,7 +46,6 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.net.http.SslCertificate; import android.net.http.SslError; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; @@ -116,6 +115,7 @@ import com.google.android.material.snackbar.Snackbar; import com.google.android.material.tabs.TabLayout; import com.stoutner.privacybrowser.BuildConfig; import com.stoutner.privacybrowser.R; +import com.stoutner.privacybrowser.asynctasks.GetHostIpAddresses; import com.stoutner.privacybrowser.dialogs.AdConsentDialog; import com.stoutner.privacybrowser.dialogs.CreateBookmarkDialog; import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog; @@ -143,13 +143,10 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.lang.ref.WeakReference; -import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -188,10 +185,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // It is also used in `onCreate()` and `checkPinnedMismatch()`. public static SslCertificate sslCertificate; - // `currentHostIpAddresses` is public static so it can be accessed from `DomainSettingsFragment` and `ViewSslCertificateDialog`. + // `currentHostIpAddresses` is public static so it can be accessed from `DomainSettingsFragment`, `GetHostIpAddresses()`, and `ViewSslCertificateDialog`. // It is also used in `onCreate()` and `GetHostIpAddresses()`. public static String currentHostIpAddresses; + // The getting IP addresses tracker is used in `onCreate() and `GetHostIpAddresses`. + public static boolean gettingIpAddresses; + + // The URL loading tracker is public static so it can be accessed from `GetHostIpAddresses`. + // It is also used in `onCreate()`, `onCreateOptionsMenu()`, `loadUrl()`, `applyDomainSettings()`, and `GetHostIpAddresses`. + public static boolean urlIsLoading; + // `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. public static String orbotStatus; @@ -272,9 +276,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`. public static String currentBookmarksFolder; - // `domainSettingsDatabaseId` is public static so it can be accessed from `PinnedMismatchDialog`. It is also used in `onCreate()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. - public static int domainSettingsDatabaseId; - // The pinned variables are public static so they can be accessed from `PinnedMismatchDialog`. They are also used in `onCreate()`, `applyDomainSettings()`, and `checkPinnedMismatch()`. public static String pinnedSslIssuedToCName; public static String pinnedSslIssuedToOName; @@ -296,12 +297,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook - // `urlIsLoading` is used in `onCreate()`, `onCreateOptionsMenu()`, `loadUrl()`, `applyDomainSettings()`, and `GetHostIpAddresses`. - private static boolean urlIsLoading; - - // `gettingIpAddresses` is used in `onCreate() and `GetHostIpAddresses`. - private static boolean gettingIpAddresses; - // `pinnedDomainSslCertificate` is used in `onCreate()`, `applyDomainSettings()`, and `checkPinnedMismatch()`. private static boolean pinnedSslCertificate; @@ -322,7 +317,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private boolean navigatingHistory; // The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, - // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, and `applyProxyThroughOrbot()`. + // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxyThroughOrbot()`, and `applyDomainSettings()`. private NestedScrollWebView currentWebView; // `fullScreenVideoFrameLayout` is used in `onCreate()` and `onConfigurationChanged()`. @@ -441,9 +436,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `waitingForOrbot` is used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. private boolean waitingForOrbot; - // `domainSettingsApplied` is used in `prepareOptionsMenu()` and `applyDomainSettings()`. - private boolean domainSettingsApplied; - // `domainSettingsJavaScriptEnabled` is used in `onOptionsItemSelected()` and `applyDomainSettings()`. private Boolean domainSettingsJavaScriptEnabled; @@ -462,9 +454,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`. private ActionBarDrawerToggle actionBarDrawerToggle; - // `urlTextBox` is used in `onCreate()`, `onOptionsItemSelected()`, `loadUrlFromTextBox()`, `loadUrl()`, and `highlightUrlText()`. - private EditText urlTextBox; - // The color spans are used in `onCreate()` and `highlightUrlText()`. private ForegroundColorSpan redColorSpan; private ForegroundColorSpan initialGrayColorSpan; @@ -578,18 +567,18 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook finalGrayColorSpan = new ForegroundColorSpan(resources.getColor(R.color.gray_500)); // Get a handle for `urlTextBox`. - urlTextBox = findViewById(R.id.url_edittext); + EditText urlEditText = findViewById(R.id.url_edittext); // Remove the formatting from `urlTextBar` when the user is editing the text. - urlTextBox.setOnFocusChangeListener((View v, boolean hasFocus) -> { + urlEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> { if (hasFocus) { // The user is editing the URL text box. // Remove the highlighting. - urlTextBox.getText().removeSpan(redColorSpan); - urlTextBox.getText().removeSpan(initialGrayColorSpan); - urlTextBox.getText().removeSpan(finalGrayColorSpan); + urlEditText.getText().removeSpan(redColorSpan); + urlEditText.getText().removeSpan(initialGrayColorSpan); + urlEditText.getText().removeSpan(finalGrayColorSpan); } else { // The user has stopped editing the URL text box. // Move to the beginning of the string. - urlTextBox.setSelection(0); + urlEditText.setSelection(0); // Reapply the highlighting. highlightUrlText(); @@ -597,7 +586,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook }); // Set the go button on the keyboard to load the URL in `urlTextBox`. - urlTextBox.setOnKeyListener((View v, int keyCode, KeyEvent event) -> { + urlEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> { // If the event is a key-down event on the `enter` button, load the URL. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { // Load the URL into the mainWebView and consume the event. @@ -713,6 +702,33 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Store the current WebView. currentWebView = webViewFragment.getView().findViewById(R.id.nestedscroll_webview); + // Store the current formatted URL string. + formattedUrlString = currentWebView.getUrl(); + + // Clear the focus from the URL text box. + urlEditText.clearFocus(); + + // Hide the soft keyboard. + inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); + + // Apply the current URL in the URL text box. + urlEditText.setText(formattedUrlString); + + // Highlight the URL text. + highlightUrlText(); + + // Set the background to indicate the domain settings status. + if (currentWebView.getDomainSettingsApplied()) { + // Set a green background on `urlTextBox` to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + if (darkTheme) { + urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + } else { + urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + } + } else { + urlEditText.setBackgroundDrawable(getResources().getDrawable(R.color.transparent)); + } + // 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. if (tabLayout.getSelectedTabPosition() != position) { // Get a handle for the corresponding tab. @@ -819,7 +835,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the `check mark` button for the `findOnPageEditText` keyboard to close the soft keyboard. findOnPageEditText.setOnKeyListener((v, keyCode, event) -> { if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { // The `enter` key was pressed. - // Hide the soft keyboard. `0` indicates no additional flags. + // Hide the soft keyboard. inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); // Consume the event. @@ -962,7 +978,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); // Clear the focus from from the URL text box and the WebView. This removes any text selection markers and context menus, which otherwise draw above the open drawers. - urlTextBox.clearFocus(); + urlEditText.clearFocus(); currentWebView.clearFocus(); } } @@ -1336,7 +1352,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem proxyThroughOrbotMenuItem = menu.findItem(R.id.proxy_through_orbot); // Set the text for the domain menu item. - if (domainSettingsApplied) { + if (currentWebView.getDomainSettingsApplied()) { addOrEditDomain.setTitle(R.string.edit_domain_settings); } else { addOrEditDomain.setTitle(R.string.add_domain_settings); @@ -1558,7 +1574,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return true; case R.id.add_or_edit_domain: - if (domainSettingsApplied) { // Edit the current domain settings. + if (currentWebView.getDomainSettingsApplied()) { // Edit the current domain settings. // Reapply the domain settings on returning to `MainWebViewActivity`. reapplyDomainSettingsOnRestart = true; currentDomainName = ""; @@ -1567,7 +1583,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook Intent domainsIntent = new Intent(this, DomainsActivity.class); // Put extra information instructing the domains activity to directly load the current domain and close on back instead of returning to the domains list. - domainsIntent.putExtra("loadDomain", domainSettingsDatabaseId); + domainsIntent.putExtra("loadDomain", currentWebView.getDomainSettingsDatabaseId()); domainsIntent.putExtra("closeOnBack", true); // Make it so. @@ -2043,7 +2059,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook if (nightMode) { // Night mode is enabled. Enable JavaScript. // Update the global variable. javaScriptEnabled = true; - } else if (domainSettingsApplied) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings. + } else if (currentWebView.getDomainSettingsApplied()) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings. // Get the JavaScript preference that was stored the last time domain settings were loaded. javaScriptEnabled = domainSettingsJavaScriptEnabled; } else { // Night mode is disabled and domain settings are not applied. Set JavaScript according to the global preference. @@ -2094,7 +2110,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.share_url: // Setup the share string. - String shareString = webViewTitle + " – " + urlTextBox.getText().toString(); + String shareString = webViewTitle + " – " + formattedUrlString; // Create the share intent. Intent shareIntent = new Intent(Intent.ACTION_SEND); @@ -3270,8 +3286,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } private void loadUrlFromTextBox() { + // Get a handle for the URL edit text. + EditText urlEditText = findViewById(R.id.url_edittext); + // Get the text from urlTextBox and convert it to a string. trim() removes white spaces from the beginning and end of the string. - String unformattedUrlString = urlTextBox.getText().toString().trim(); + String unformattedUrlString = urlEditText.getText().toString().trim(); // Check to see if `unformattedUrlString` is a valid URL. Otherwise, convert it into a search. if (unformattedUrlString.startsWith("content://")) { @@ -3330,8 +3349,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = searchURL + encodedUrlString; } - // Clear the focus from the URL text box. Otherwise, proximate typing in the box will retain the colorized formatting instead of being reset during refocus. - urlTextBox.clearFocus(); + // Clear the focus from the URL edit text. Otherwise, proximate typing in the box will retain the colorized formatting instead of being reset during refocus. + urlEditText.clearFocus(); // Make it so. loadUrl(formattedUrlString); @@ -3559,21 +3578,26 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Close `domainNameCursor. domainNameCursor.close(); - // Initialize variables to track if domain settings will be applied and, if so, under which name. - domainSettingsApplied = false; + // Initialize the domain name in database variable. String domainNameInDatabase = null; - // Check the hostname. - if (domainSettingsSet.contains(hostName)) { - domainSettingsApplied = true; + // Check the hostname against the domain settings set. + if (domainSettingsSet.contains(hostName)) { // The hostname is contained in the domain settings set. + // Record the domain name in the database. domainNameInDatabase = hostName; + + // Set the domain settings applied tracker to true. + currentWebView.setDomainSettingsApplied(true); + } else { // The hostname is not contained in the domain settings set. + // Set the domain settings applied tracker to false. + currentWebView.setDomainSettingsApplied(false); } // Check all the subdomains of the host name against wildcard domains in the domain cursor. - while (!domainSettingsApplied && hostName.contains(".")) { // Stop checking if domain settings are already applied or there are no more `.` in the host name. + while (!currentWebView.getDomainSettingsApplied() && hostName.contains(".")) { // Stop checking if domain settings are already applied or there are no more `.` in the host name. if (domainSettingsSet.contains("*." + hostName)) { // Check the host name prepended by `*.`. - // Apply the domain settings. - domainSettingsApplied = true; + // Set the domain settings applied tracker to true. + currentWebView.setDomainSettingsApplied(true); // Store the applied domain names as it appears in the database. domainNameInDatabase = "*." + hostName; @@ -3595,13 +3619,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nightMode = sharedPreferences.getBoolean("night_mode", false); boolean displayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true); - if (domainSettingsApplied) { // The url has custom domain settings. + if (currentWebView.getDomainSettingsApplied()) { // The url has custom domain settings. // Get a cursor for the current host and move it to the first position. Cursor currentHostDomainSettingsCursor = domainsDatabaseHelper.getCursorForDomainName(domainNameInDatabase); currentHostDomainSettingsCursor.moveToFirst(); // Get the settings from the cursor. - domainSettingsDatabaseId = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); + currentWebView.setDomainSettingsDatabaseId(currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); javaScriptEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); firstPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1); thirdPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1); @@ -3775,7 +3799,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook break; } - // Set a green background on `urlTextBox` to indicate that custom domain settings are being used. We have to use the deprecated `.getDrawable()` until the minimum API >= 21. + // Set a green background on URL edit text to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. if (darkTheme) { urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); } else { @@ -3813,7 +3837,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Reset the pinned variables. - domainSettingsDatabaseId = -1; + currentWebView.setDomainSettingsDatabaseId(-1); pinnedSslCertificate = false; pinnedSslIssuedToCName = ""; pinnedSslIssuedToOName = ""; @@ -3869,7 +3893,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the loading of webpage images. currentWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImages); - // Set a transparent background on `urlTextBox`. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + // Set a transparent background on URL edit text. The deprecated `.getDrawable()` must be used until the minimum API >= 21. urlEditText.setBackgroundDrawable(getResources().getDrawable(R.color.transparent)); } @@ -4058,18 +4082,21 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } private void highlightUrlText() { + // Get a handle for the URL edit text. + EditText urlEditText = findViewById(R.id.url_edittext); + // Only highlight the URL text if the box is not currently selected. - if (!urlTextBox.hasFocus()) { + if (!urlEditText.hasFocus()) { // Get the URL string. - String urlString = urlTextBox.getText().toString(); + String urlString = urlEditText.getText().toString(); // Highlight the URL according to the protocol. if (urlString.startsWith("file://")) { // This is a file URL. // De-emphasize only the protocol. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } else if (urlString.startsWith("content://")) { // De-emphasize only the protocol. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } else { // This is a web URL. // Get the index of the `/` immediately after the domain name. int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2)); @@ -4094,25 +4121,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Markup the beginning of the URL. if (urlString.startsWith("http://")) { // Highlight the protocol of connections that are not encrypted. - urlTextBox.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); // De-emphasize subdomains. if (penultimateDotIndex > 0) { // There is more than one subdomain in the domain name. - urlTextBox.getText().setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } else if (urlString.startsWith("https://")) { // De-emphasize the protocol of connections that are encrypted. if (penultimateDotIndex > 0) { // There is more than one subdomain in the domain name. // De-emphasize the protocol and the additional subdomains. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } else { // There is only one subdomain in the domain name. // De-emphasize only the protocol. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } // De-emphasize the text after the domain name. if (endOfDomainName > 0) { - urlTextBox.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } } @@ -4197,7 +4224,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook startActivity(openWithBrowserIntent); } - private static void checkPinnedMismatch() { + public static void checkPinnedMismatch(int domainSettingsDatabaseId) { if ((pinnedSslCertificate || pinnedIpAddresses) && !ignorePinnedDomainInformation) { // Initialize the current SSL certificate variables. String currentWebsiteIssuedToCName = ""; @@ -4253,7 +4280,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook !currentWebsiteSslEndDateString.equals(pinnedSslEndDateString)))) { // Get a handle for the pinned mismatch alert dialog. - DialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(pinnedSslCertificate, pinnedIpAddresses); + DialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(domainSettingsDatabaseId, pinnedSslCertificate, pinnedIpAddresses); // Show the pinned mismatch alert dialog. pinnedMismatchDialogFragment.show(fragmentManager, "Pinned Mismatch"); @@ -4261,95 +4288,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `String` contains the results. - private static class GetHostIpAddresses extends AsyncTask { - // The weak references are used to determine if the activity have disappeared while the AsyncTask is running. - private final WeakReference activityWeakReference; - - GetHostIpAddresses(Activity activity) { - // Populate the weak references. - activityWeakReference = new WeakReference<>(activity); - } - - // `onPreExecute()` operates on the UI thread. - @Override - protected void onPreExecute() { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - return; - } - - // Set the getting IP addresses tracker. - gettingIpAddresses = true; - } - - - @Override - protected String doInBackground(String... domainName) { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - // Return an empty spannable string builder. - return ""; - } - - // Initialize an IP address string builder. - StringBuilder ipAddresses = new StringBuilder(); - - // Get an array with the IP addresses for the host. - try { - // Get an array with all the IP addresses for the domain. - InetAddress[] inetAddressesArray = InetAddress.getAllByName(domainName[0]); - - // Add each IP address to the string builder. - for (InetAddress inetAddress : inetAddressesArray) { - if (ipAddresses.length() == 0) { // This is the first IP address. - // Add the IP address to the string builder. - ipAddresses.append(inetAddress.getHostAddress()); - } else { // This is not the first IP address. - // Add a line break to the string builder first. - ipAddresses.append("\n"); - - // Add the IP address to the string builder. - ipAddresses.append(inetAddress.getHostAddress()); - } - } - } catch (UnknownHostException exception) { - // Do nothing. - } - - // Return the string. - return ipAddresses.toString(); - } - - // `onPostExecute()` operates on the UI thread. - @Override - protected void onPostExecute(String ipAddresses) { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - return; - } - - // Store the IP addresses. - currentHostIpAddresses = ipAddresses; - - if (!urlIsLoading) { - checkPinnedMismatch(); - } - - // Reset the getting IP addresses tracker. - gettingIpAddresses = false; - } - } - private class WebViewPagerAdapter extends FragmentPagerAdapter { // The WebView fragments list contains all the WebViews. private LinkedList webViewFragmentsList = new LinkedList<>(); @@ -4453,6 +4391,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook final DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); final RelativeLayout mainContentRelativeLayout = findViewById(R.id.main_content_relativelayout); final ActionBar actionBar = getSupportActionBar(); + EditText urlEditText = findViewById(R.id.url_edittext); final TabLayout tabLayout = findViewById(R.id.tablayout); final SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swiperefreshlayout); @@ -5166,7 +5105,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = url; // Display the formatted URL text. - urlTextBox.setText(formattedUrlString); + urlEditText.setText(formattedUrlString); // Apply text highlighting to `urlTextBox`. highlightUrlText(); @@ -5175,7 +5114,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook Uri currentUri = Uri.parse(formattedUrlString); // Get the IP addresses for the host. - new GetHostIpAddresses(activity).execute(currentUri.getHost()); + new GetHostIpAddresses(activity, currentWebView.getDomainSettingsDatabaseId()).execute(currentUri.getHost()); // Apply any custom domain settings if the URL was loaded by navigating history. if (navigatingHistory) { @@ -5266,13 +5205,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set `formattedUrlString` to `""`. formattedUrlString = ""; - urlTextBox.setText(formattedUrlString); + urlEditText.setText(formattedUrlString); // Request focus for `urlTextBox`. - urlTextBox.requestFocus(); + urlEditText.requestFocus(); // Display the keyboard. - inputMethodManager.showSoftInput(urlTextBox, 0); + inputMethodManager.showSoftInput(urlEditText, 0); // Apply the domain settings. This clears any settings from the previous domain. applyDomainSettings(formattedUrlString, true, false); @@ -5281,9 +5220,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = nestedScrollWebView.getUrl(); // Only update the URL text box if the user is not typing in it. - if (!urlTextBox.hasFocus()) { + if (!urlEditText.hasFocus()) { // Display the formatted URL text. - urlTextBox.setText(formattedUrlString); + urlEditText.setText(formattedUrlString); // Apply text highlighting to `urlTextBox`. highlightUrlText(); @@ -5295,7 +5234,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Check the current website information against any pinned domain information if the current IP addresses have been loaded. if (!gettingIpAddresses) { - checkPinnedMismatch(); + checkPinnedMismatch(currentWebView.getDomainSettingsDatabaseId()); } } diff --git a/app/src/main/java/com/stoutner/privacybrowser/asynctasks/GetHostIpAddresses.java b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/GetHostIpAddresses.java new file mode 100644 index 00000000..1e004d13 --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/GetHostIpAddresses.java @@ -0,0 +1,122 @@ +/* + * Copyright © 2019 Soren Stoutner . + * + * This file is part of Privacy Browser . + * + * Privacy Browser is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser. If not, see . + */ + +package com.stoutner.privacybrowser.asynctasks; + +import android.app.Activity; +import android.os.AsyncTask; + +import com.stoutner.privacybrowser.activities.MainWebViewActivity; + +import java.lang.ref.WeakReference; +import java.net.InetAddress; +import java.net.UnknownHostException; + +// This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `String` contains the results. +public class GetHostIpAddresses extends AsyncTask { + // The weak references are used to determine if the activity have disappeared while the AsyncTask is running. + private final WeakReference activityWeakReference; + private final int domainSettingsDatabaseId; + + public GetHostIpAddresses(Activity activity, int domainSettingsDatabaseId) { + // Populate the weak activity reference. + activityWeakReference = new WeakReference<>(activity); + + // Populate the domain settings database ID. + this.domainSettingsDatabaseId = domainSettingsDatabaseId; + } + + // `onPreExecute()` operates on the UI thread. + @Override + protected void onPreExecute() { + // Get a handle for the activity. + Activity activity = activityWeakReference.get(); + + // Abort if the activity is gone. + if ((activity == null) || activity.isFinishing()) { + return; + } + + // Set the getting IP addresses tracker. + MainWebViewActivity.gettingIpAddresses = true; + } + + + @Override + protected String doInBackground(String... domainName) { + // Get a handle for the activity. + Activity activity = activityWeakReference.get(); + + // Abort if the activity is gone. + if ((activity == null) || activity.isFinishing()) { + // Return an empty spannable string builder. + return ""; + } + + // Initialize an IP address string builder. + StringBuilder ipAddresses = new StringBuilder(); + + // Get an array with the IP addresses for the host. + try { + // Get an array with all the IP addresses for the domain. + InetAddress[] inetAddressesArray = InetAddress.getAllByName(domainName[0]); + + // Add each IP address to the string builder. + for (InetAddress inetAddress : inetAddressesArray) { + if (ipAddresses.length() == 0) { // This is the first IP address. + // Add the IP address to the string builder. + ipAddresses.append(inetAddress.getHostAddress()); + } else { // This is not the first IP address. + // Add a line break to the string builder first. + ipAddresses.append("\n"); + + // Add the IP address to the string builder. + ipAddresses.append(inetAddress.getHostAddress()); + } + } + } catch (UnknownHostException exception) { + // Do nothing. + } + + // Return the string. + return ipAddresses.toString(); + } + + // `onPostExecute()` operates on the UI thread. + @Override + protected void onPostExecute(String ipAddresses) { + // Get a handle for the activity. + Activity activity = activityWeakReference.get(); + + // Abort if the activity is gone. + if ((activity == null) || activity.isFinishing()) { + return; + } + + // Store the IP addresses. + MainWebViewActivity.currentHostIpAddresses = ipAddresses; + + if (!MainWebViewActivity.urlIsLoading) { + MainWebViewActivity.checkPinnedMismatch(domainSettingsDatabaseId); + } + + // Reset the getting IP addresses tracker. + MainWebViewActivity.gettingIpAddresses = false; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java index e1c035ae..7e86bbdb 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java @@ -83,13 +83,14 @@ public class PinnedMismatchDialog extends DialogFragment { pinnedMismatchListener = (PinnedMismatchListener) context; } - public static PinnedMismatchDialog displayDialog(boolean pinnedSslCertificate, boolean pinnedIpAddresses) { + public static PinnedMismatchDialog displayDialog(int domainSettingsDatabaseId, boolean pinnedSslCertificate, boolean pinnedIpAddresses) { // Create an arguments bundle. Bundle argumentsBundle = new Bundle(); // Store the variables in the bundle. - argumentsBundle.putBoolean("Pinned_SSL_Certificate", pinnedSslCertificate); - argumentsBundle.putBoolean("Pinned_IP_Addresses", pinnedIpAddresses); + argumentsBundle.putInt("domain_settings_database_id", domainSettingsDatabaseId); + argumentsBundle.putBoolean("pinned_sss_certificate", pinnedSslCertificate); + argumentsBundle.putBoolean("pinned_ip_addresses", pinnedIpAddresses); // Add the arguments bundle to this instance of `PinnedMismatchDialog`. PinnedMismatchDialog thisPinnedMismatchDialog = new PinnedMismatchDialog(); @@ -124,8 +125,9 @@ public class PinnedMismatchDialog extends DialogFragment { assert getArguments() != null; // Get the variables from the bundle. - pinnedSslCertificate = getArguments().getBoolean("Pinned_SSL_Certificate"); - pinnedIpAddresses = getArguments().getBoolean("Pinned_IP_Addresses"); + int domainSettingsDatabaseId = getArguments().getInt("domain_settings_database_id"); + pinnedSslCertificate = getArguments().getBoolean("pinned_ssl_certificate"); + pinnedIpAddresses = getArguments().getBoolean("pinned_ip_addresses"); // Set the favorite icon as the dialog icon if it exists. if (MainWebViewActivity.favoriteIconBitmap.equals(MainWebViewActivity.favoriteIconDefaultBitmap)) { // There is no favorite icon. @@ -164,7 +166,7 @@ public class PinnedMismatchDialog extends DialogFragment { // Update the SSL certificate if it is pinned. if (pinnedSslCertificate) { // Update the pinned SSL certificate in the domain database. - domainsDatabaseHelper.updatePinnedSslCertificate(MainWebViewActivity.domainSettingsDatabaseId, currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName, + domainsDatabaseHelper.updatePinnedSslCertificate(domainSettingsDatabaseId, currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName, currentSslIssuedByCName, currentSslIssuedByOName, currentSslIssuedByUName, currentSslStartDateLong, currentSslEndDateLong); // Update the pinned SSL certificate class variables to match the information that is now in the database. @@ -181,7 +183,7 @@ public class PinnedMismatchDialog extends DialogFragment { // Update the IP addresses if they are pinned. if (pinnedIpAddresses) { // Update the pinned IP addresses in the domain database. - domainsDatabaseHelper.updatePinnedIpAddresses(MainWebViewActivity.domainSettingsDatabaseId, MainWebViewActivity.currentHostIpAddresses); + domainsDatabaseHelper.updatePinnedIpAddresses(domainSettingsDatabaseId, MainWebViewActivity.currentHostIpAddresses); // Update the pinned IP addresses class variable to match the information that is now in the database. MainWebViewActivity.pinnedHostIpAddresses = MainWebViewActivity.currentHostIpAddresses; diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java index 44bc9ef1..5044b27d 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java +++ b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java @@ -36,6 +36,10 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild // The previous Y position needs to be tracked between motion events. private int previousYPosition; + // Track if domain settings are applied to this nested scroll WebView and, if so, the database ID. + private boolean domainSettingsApplied; + private int domainSettingsDatabaseId; + // Basic constructor. public NestedScrollWebView(Context context) { // Roll up to the next constructor. @@ -60,6 +64,26 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild nestedScrollingChildHelper.setNestedScrollingEnabled(true); } + public void setDomainSettingsApplied(boolean applied) { + // Store the domain settings applied status. + domainSettingsApplied = applied; + } + + public boolean getDomainSettingsApplied() { + // Return the domain settings applied status. + return domainSettingsApplied; + } + + public void setDomainSettingsDatabaseId(int databaseId) { + // Store the domain settings database ID. + domainSettingsDatabaseId = databaseId; + } + + public int getDomainSettingsDatabaseId() { + // Return the domain settings database ID. + return domainSettingsDatabaseId; + } + @Override public boolean onTouchEvent(MotionEvent motionEvent) { // Initialize a tracker to return if this motion event is handled. -- 2.45.2