X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FMainWebViewActivity.java;h=c2d65ec51447b4a49224aafaef2d192684e25bcc;hp=16a02ad24b91d17e4086abe081010b0b77a4c246;hb=08835c5331d9fde1078d29027c821a4dfa6eb3a7;hpb=560d0030d352407816b4167025a89e54808b29e9 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 16a02ad2..c2d65ec5 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -26,6 +26,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.app.DialogFragment; import android.app.DownloadManager; +import android.app.SearchManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ClipData; @@ -75,6 +76,7 @@ import android.text.Editable; import android.text.Spanned; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; +import android.util.Log; import android.util.Patterns; import android.view.ContextMenu; import android.view.GestureDetector; @@ -577,11 +579,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // 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. - try { - loadUrlFromTextBox(); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } + loadUrlFromTextBox(); + // If the enter key was pressed, consume the event. return true; } else { @@ -815,11 +814,18 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); - // Implement swipe to refresh - swipeRefreshLayout = findViewById(R.id.swipe_refreshlayout); - swipeRefreshLayout.setColorSchemeResources(R.color.blue_700); + // Implement swipe to refresh. + swipeRefreshLayout = findViewById(R.id.swiperefreshlayout); swipeRefreshLayout.setOnRefreshListener(() -> mainWebView.reload()); + // Set the swipe to refresh color according to the theme. + if (darkTheme) { + swipeRefreshLayout.setColorSchemeResources(R.color.blue_600); + swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.gray_850); + } else { + swipeRefreshLayout.setColorSchemeResources(R.color.blue_700); + } + // `DrawerTitle` identifies the `DrawerLayouts` in accessibility mode. drawerLayout.setDrawerTitle(GravityCompat.START, getString(R.string.navigation_drawer)); drawerLayout.setDrawerTitle(GravityCompat.END, getString(R.string.bookmarks)); @@ -922,7 +928,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Hide the keyboard (if displayed). inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0); - // Clear the focus from from the URL text box and the WebView. This removes any text selection markers and context menues, which otherwise draw above the open drawers. + // 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(); mainWebView.clearFocus(); } @@ -1200,17 +1206,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Initialize the default preference values the first time the program is run. `false` keeps this command from resetting any current preferences back to default. PreferenceManager.setDefaultValues(this, R.xml.preferences, false); - // Get the intent that started the app. - final Intent launchingIntent = getIntent(); - - // Extract the launching intent data as `launchingIntentUriData`. - final Uri launchingIntentUriData = launchingIntent.getData(); - - // Convert the launching intent URI data (if it exists) to a string and store it in `formattedUrlString`. - if (launchingIntentUriData != null) { - formattedUrlString = launchingIntentUriData.toString(); - } - // Get a handle for the `Runtime`. privacyBrowserRuntime = Runtime.getRuntime(); @@ -1287,10 +1282,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = ""; // Apply the domain settings for the new URL. `applyDomainSettings` doesn't do anything if the domain has not changed. - applyDomainSettings(url, true, false); + boolean userAgentChanged = applyDomainSettings(url, true, false); - // Returning false causes the current WebView to handle the URL and prevents it from adding redirects to the history list. - return false; + // Check if the user agent has changed. + if (userAgentChanged) { + // Manually load the URL. The changing of the user agent will cause WebView to reload the previous URL. + mainWebView.loadUrl(url, customHeaders); + + // Returning true indicates that Privacy Browser is manually handling the loading of the URL. + return true; + } else { + // Returning false causes the current WebView to handle the URL and prevents it from adding redirects to the history list. + return false; + } } else if (url.startsWith("mailto:")) { // Load the email address in an external email program. // Use `ACTION_SENDTO` instead of `ACTION_SEND` so that only email programs are launched. Intent emailIntent = new Intent(Intent.ACTION_SENDTO); @@ -1585,11 +1589,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Apply any custom domain settings if the URL was loaded by navigating history. if (navigatingHistory) { + // Apply the domain settings. + boolean userAgentChanged = applyDomainSettings(url, true, false); + // Reset `navigatingHistory`. navigatingHistory = false; - // Apply the domain settings. - applyDomainSettings(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(formattedUrlString); + } } // Set `urlIsLoading` to `true`, so that redirects while loading do not trigger changes in the user agent, which forces another reload of the existing page. @@ -1699,7 +1708,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook sslCertificate = mainWebView.getCertificate(); // Check the current website SSL certificate against the pinned SSL certificate if there is a pinned SSL certificate the user has not chosen to ignore it for this session. - if (pinnedDomainSslCertificate && !ignorePinnedSslCertificate) { + // Also ignore if changes in the user agent causes an error while navigating history. + if (pinnedDomainSslCertificate && !ignorePinnedSslCertificate && navigatingHistory) { // Initialize the current SSL certificate variables. String currentWebsiteIssuedToCName = ""; String currentWebsiteIssuedToOName = ""; @@ -1796,6 +1806,34 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); + // Get the intent that started the app. + Intent launchingIntent = getIntent(); + + // Get the information from the intent. + String launchingIntentAction = launchingIntent.getAction(); + Uri launchingIntentUriData = launchingIntent.getData(); + + // If the intent action is a web search, perform the search. + if ((launchingIntentAction != null) && launchingIntentAction.equals(Intent.ACTION_WEB_SEARCH)) { + // Create an encoded URL string. + String encodedUrlString; + + Log.i("Intent", launchingIntent.getStringExtra(SearchManager.QUERY)); + + // Sanitize the search input and convert it to a search. + try { + encodedUrlString = URLEncoder.encode(launchingIntent.getStringExtra(SearchManager.QUERY), "UTF-8"); + } catch (UnsupportedEncodingException exception) { + encodedUrlString = ""; + } + + // Add the base search URL. + formattedUrlString = searchURL + encodedUrlString; + } else if (launchingIntentUriData != null){ // Check to see if the intent contains a new URL. + // Set the formatted URL string. + formattedUrlString = launchingIntentUriData.toString(); + } + // Load the website if not waiting for Orbot to connect. if (!waitingForOrbot) { loadUrl(formattedUrlString); @@ -1807,27 +1845,46 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Sets the new intent as the activity intent, so that any future `getIntent()`s pick up this one instead of creating a new activity. setIntent(intent); - // Check to see if the intent contains a new URL. - if (intent.getData() != null) { - // Get the intent data. - final Uri intentUriData = intent.getData(); + Log.i("Intent", intent.getAction()); - // Load the website. - loadUrl(intentUriData.toString()); + // Get the information from the intent. + String intentAction = intent.getAction(); + Uri intentUriData = intent.getData(); - // Close the navigation drawer if it is open. - if (drawerLayout.isDrawerVisible(GravityCompat.START)) { - drawerLayout.closeDrawer(GravityCompat.START); - } + // If the intent action is a web search, perform the search. + if ((intentAction != null) && intentAction.equals(Intent.ACTION_WEB_SEARCH)) { + // Create an encoded URL string. + String encodedUrlString; - // Close the bookmarks drawer if it is open. - if (drawerLayout.isDrawerVisible(GravityCompat.END)) { - drawerLayout.closeDrawer(GravityCompat.END); + // Sanitize the search input and convert it to a search. + try { + encodedUrlString = URLEncoder.encode(intent.getStringExtra(SearchManager.QUERY), "UTF-8"); + } catch (UnsupportedEncodingException exception) { + encodedUrlString = ""; } - // Clear the keyboard if displayed and remove the focus on the urlTextBar if it has it. - mainWebView.requestFocus(); + // Add the base search URL. + formattedUrlString = searchURL + encodedUrlString; + } else if (intentUriData != null){ // Check to see if the intent contains a new URL. + // Set the formatted URL string. + formattedUrlString = intentUriData.toString(); + } + + // Load the URL. + loadUrl(formattedUrlString); + + // Close the navigation drawer if it is open. + if (drawerLayout.isDrawerVisible(GravityCompat.START)) { + drawerLayout.closeDrawer(GravityCompat.START); + } + + // Close the bookmarks drawer if it is open. + if (drawerLayout.isDrawerVisible(GravityCompat.END)) { + drawerLayout.closeDrawer(GravityCompat.END); } + + // Clear the keyboard if displayed and remove the focus on the urlTextBar if it has it. + mainWebView.requestFocus(); } @Override @@ -2743,7 +2800,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); // Get the JavaScript preference. - javaScriptEnabled = sharedPreferences.getBoolean("javascript_enabled", false); + javaScriptEnabled = sharedPreferences.getBoolean("javascript", false); } // Apply the JavaScript setting to the WebView. @@ -3806,7 +3863,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - private void loadUrlFromTextBox() throws UnsupportedEncodingException { + private void loadUrlFromTextBox() { // 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(); @@ -3828,24 +3885,36 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // The ternary operator (? :) makes sure that a null pointer exception is not thrown, which would happen if `.get` was called on a `null` value. - final String scheme = unformattedUrl != null ? unformattedUrl.getProtocol() : null; - final String authority = unformattedUrl != null ? unformattedUrl.getAuthority() : null; - final String path = unformattedUrl != null ? unformattedUrl.getPath() : null; - final String query = unformattedUrl != null ? unformattedUrl.getQuery() : null; - final String fragment = unformattedUrl != null ? unformattedUrl.getRef() : null; + String scheme = unformattedUrl != null ? unformattedUrl.getProtocol() : null; + String authority = unformattedUrl != null ? unformattedUrl.getAuthority() : null; + String path = unformattedUrl != null ? unformattedUrl.getPath() : null; + String query = unformattedUrl != null ? unformattedUrl.getQuery() : null; + String fragment = unformattedUrl != null ? unformattedUrl.getRef() : null; // Build the URI. Uri.Builder formattedUri = new Uri.Builder(); formattedUri.scheme(scheme).authority(authority).path(path).query(query).fragment(fragment); // Decode `formattedUri` as a `String` in `UTF-8`. - formattedUrlString = URLDecoder.decode(formattedUri.build().toString(), "UTF-8"); + try { + formattedUrlString = URLDecoder.decode(formattedUri.build().toString(), "UTF-8"); + } catch (UnsupportedEncodingException exception) { + // Load a blank string. + formattedUrlString = ""; + } } else if (unformattedUrlString.isEmpty()){ // Load a blank web site. // Load a blank string. formattedUrlString = ""; } else { // Search for the contents of the URL box. - // Sanitize the search input and convert it to a search. - final String encodedUrlString = URLEncoder.encode(unformattedUrlString, "UTF-8"); + // Create an encoded URL String. + String encodedUrlString; + + // Sanitize the search input. + try { + encodedUrlString = URLEncoder.encode(unformattedUrlString, "UTF-8"); + } catch (UnsupportedEncodingException exception) { + encodedUrlString = ""; + } // Add the base search URL. formattedUrlString = searchURL + encodedUrlString; @@ -3986,7 +4055,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `reloadWebsite` is used if returning from the Domains activity. Otherwise JavaScript might not function correctly if it is newly enabled. // The deprecated `.getDrawable()` must be used until the minimum API >= 21. @SuppressWarnings("deprecation") - private void applyDomainSettings(String url, boolean resetFavoriteIcon, boolean reloadWebsite) { + private boolean applyDomainSettings(String url, boolean resetFavoriteIcon, boolean reloadWebsite) { + // Get the current user agent. + String initialUserAgent = mainWebView.getSettings().getUserAgentString(); + + // Initialize a variable to track if the user agent changes. + boolean userAgentChanged = false; + // Parse the URL into a URI. Uri uri = Uri.parse(url); @@ -4223,25 +4298,28 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // Set swipe to refresh. - switch (swipeToRefreshInt) { - case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT: - // Set swipe to refresh according to the default. - swipeRefreshLayout.setEnabled(defaultSwipeToRefresh); - break; + // Store the applied user agent string, which is used in the View Source activity. + appliedUserAgentString = mainWebView.getSettings().getUserAgentString(); - case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED: - // Enable swipe to refresh. - swipeRefreshLayout.setEnabled(true); - break; + // Update the user agent change tracker. + userAgentChanged = !appliedUserAgentString.equals(initialUserAgent); + } - case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED: - // Disable swipe to refresh. - swipeRefreshLayout.setEnabled(false); - } + // Set swipe to refresh. + switch (swipeToRefreshInt) { + case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT: + // Set swipe to refresh according to the default. + swipeRefreshLayout.setEnabled(defaultSwipeToRefresh); + break; - // Store the applied user agent string, which is used in the View Source activity. - appliedUserAgentString = mainWebView.getSettings().getUserAgentString(); + case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED: + // Enable swipe to refresh. + swipeRefreshLayout.setEnabled(true); + break; + + case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED: + // Disable swipe to refresh. + swipeRefreshLayout.setEnabled(false); } // Set the loading of webpage images. @@ -4267,15 +4345,15 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } else { // The new URL does not have custom domain settings. Load the defaults. // Store the values from `sharedPreferences` in variables. - javaScriptEnabled = sharedPreferences.getBoolean("javascript_enabled", false); - firstPartyCookiesEnabled = sharedPreferences.getBoolean("first_party_cookies_enabled", false); - thirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies_enabled", false); - domStorageEnabled = sharedPreferences.getBoolean("dom_storage_enabled", false); - saveFormDataEnabled = sharedPreferences.getBoolean("save_form_data_enabled", false); // Form data can be removed once the minimum API >= 26. + javaScriptEnabled = sharedPreferences.getBoolean("javascript", false); + firstPartyCookiesEnabled = sharedPreferences.getBoolean("first_party_cookies", false); + thirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false); + domStorageEnabled = sharedPreferences.getBoolean("dom_storage", false); + saveFormDataEnabled = sharedPreferences.getBoolean("save_form_data", false); // Form data can be removed once the minimum API >= 26. easyListEnabled = sharedPreferences.getBoolean("easylist", true); easyPrivacyEnabled = sharedPreferences.getBoolean("easyprivacy", true); - fanboysAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboy_annoyance_list", true); - fanboysSocialBlockingListEnabled = sharedPreferences.getBoolean("fanboy_social_blocking_list", true); + fanboysAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboys_annoyance_list", true); + fanboysSocialBlockingListEnabled = sharedPreferences.getBoolean("fanboys_social_blocking_list", true); ultraPrivacyEnabled = sharedPreferences.getBoolean("ultraprivacy", true); blockAllThirdPartyRequests = sharedPreferences.getBoolean("block_all_third_party_requests", false); @@ -4343,6 +4421,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Store the applied user agent string, which is used in the View Source activity. appliedUserAgentString = mainWebView.getSettings().getUserAgentString(); + + // Update the user agent change tracker. + userAgentChanged = !appliedUserAgentString.equals(initialUserAgent); } // Set the loading of webpage images. @@ -4365,6 +4446,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook if (reloadWebsite) { mainWebView.reload(); } + + // Return the user agent changed status. + return userAgentChanged; } private void applyProxyThroughOrbot(boolean reloadWebsite) { @@ -4528,17 +4612,48 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } private void highlightUrlText() { + // Get the URL string. String urlString = urlTextBox.getText().toString(); + // Get the index of the `/` immediately after the domain name. + int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2)); + + // Create a base URL string. + String baseUrl; + + // Get the base URL. + if (endOfDomainName > 0) { // There is at least one character after the base URL. + // Get the base URL. + baseUrl = urlString.substring(0, endOfDomainName); + } else { // There are no characters after the base URL. + // Set the base URL to be the entire URL string. + baseUrl = urlString; + } + + // Get the index of the last `.` in the domain. + int lastDotIndex = baseUrl.lastIndexOf("."); + + // Get the index of the penultimate `.` in the domain. + int penultimateDotIndex = baseUrl.lastIndexOf(".", lastDotIndex - 1); + + // 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); + + // 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); + } } else if (urlString.startsWith("https://")) { // De-emphasize the protocol of connections that are encrypted. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + 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); + } 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); + } } - // Get the index of the `/` immediately after the domain name. - int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2)); - // De-emphasize the text after the domain name. if (endOfDomainName > 0) { urlTextBox.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);