Allow loading of hosts that are not fQDNs from the URL text box. Fixes https://redmi...
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.java
index 292292fa0f3565a1c3f92ca2d698d8f7ed58716b..3c832ae3ed2ec5806ac596f6dfa6f9a0f467d80e 100644 (file)
@@ -194,15 +194,18 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     // 'homepage' is used in `onCreate()`, `onNavigationItemSelected()`, and `applyAppSettings()`.
     private String homepage;
 
-    // `javaScriptDisabledSearchURL` is used in `loadURLFromTextBox()` and `applyAppSettings()`.
-    private String javaScriptDisabledSearchURL;
-
-    // `javaScriptEnabledSearchURL` is used in `loadURLFromTextBox()` and `applyAppSettings()`.
-    private String javaScriptEnabledSearchURL;
+    // `searchURL` is used in `loadURLFromTextBox()` and `applyAppSettings()`.
+    private String searchURL;
 
     // `adBlockerEnabled` is used in `onCreate()` and `applyAppSettings()`.
     private boolean adBlockerEnabled;
 
+    // `privacyBrowserRuntime` is used in `onCreate()` and `applyAppSettings()`.
+    Runtime privacyBrowserRuntime;
+
+    // `incognitoModeEnabled` is used in `onCreate()` and `applyAppSettings()`.
+    private boolean incognitoModeEnabled;
+
     // `fullScreenBrowsingModeEnabled` is used in `onCreate()` and `applyAppSettings()`.
     private boolean fullScreenBrowsingModeEnabled;
 
@@ -215,18 +218,18 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     // `translucentNavigationBarOnFullscreen` is used in `onCreate()` and `applyAppSettings()`.
     private boolean translucentNavigationBarOnFullscreen;
 
-    // `proxyThroughOrbot` is used in `onCreate()` and `applyAppSettings()`.
-    private boolean proxyThroughOrbot;
-
     // `currentDomainName` is used in `onCreate(), `onNavigationItemSelected()`, and `applyDomainSettings()`.
     private String currentDomainName;
 
-    // `pendingUrl` is used in `onCreate()` and `applyAppSettings()`.
-    private static String pendingUrl;
+    // `waitingForOrbot` is used in `onCreate()` and `applyAppSettings()`.
+    private boolean waitingForOrbot;
 
     // `waitingForOrbotData` is used in `onCreate()` and `applyAppSettings()`.
     private String waitingForOrbotHTMLString;
 
+    // `privateDataDirectoryString` is used in `onCreate()` and `onNavigationItemSelected()`.
+    private String privateDataDirectoryString;
+
     // `findOnPageLinearLayout` is used in `onCreate()`, `onOptionsItemSelected()`, and `closeFindOnPage()`.
     private LinearLayout findOnPageLinearLayout;
 
@@ -304,10 +307,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         // Set `waitingForOrbotHTMLString`.
         waitingForOrbotHTMLString = "<html><body><br/><center><h1>" + getString(R.string.waiting_for_orbot) + "</h1></center></body></html>";
 
-        // Initialize `currentDomainName`, `pendingUrl`, and `orbotStatus`.
+        // Initialize `currentDomainName`, `orbotStatus`, and `waitingForOrbot`.
         currentDomainName = "";
-        pendingUrl = "";
         orbotStatus = "unknown";
+        waitingForOrbot = false;
 
         // Create an Orbot status `BroadcastReceiver`.
         BroadcastReceiver orbotStatusBroadcastReceiver = new BroadcastReceiver() {
@@ -316,19 +319,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 // Store the content of the status message in `orbotStatus`.
                 orbotStatus = intent.getStringExtra("org.torproject.android.intent.extra.STATUS");
 
-                // If we are waiting on `pendingUrl`, load it now that Orbot is connected.
-                if (orbotStatus.equals("ON") && !pendingUrl.isEmpty()) {
-
-                    // Wait 500 milliseconds, because Orbot isn't really ready yet.
-                    try {
-                        Thread.sleep(500);
-                    } catch (InterruptedException exception) {
-                        // Do nothing.
-                    }
-
-                    // Copy `pendingUrl` to `formattedUrlString` and reset `pendingUrl` to be empty.
-                    formattedUrlString = pendingUrl;
-                    pendingUrl = "";
+                // If we are waiting on Orbot, load the website now that Orbot is connected.
+                if (orbotStatus.equals("ON") && waitingForOrbot) {
+                    // Reset `waitingForOrbot`.
+                    waitingForOrbot = false;
 
                     // Load `formattedUrlString
                     loadUrl(formattedUrlString);
@@ -638,7 +632,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 webViewTitle = getString(R.string.no_title);
 
                 // Check to see if we are waiting on Orbot.
-                if (pendingUrl.isEmpty()) {  // We are not waiting on Orbot, so we need to process the URL.
+                if (!waitingForOrbot) {  // We are not waiting on Orbot, so we need to process the URL.
                     // We need to update `formattedUrlString` at the beginning of the load, so that if the user toggles JavaScript during the load the new website is reloaded.
                     formattedUrlString = url;
 
@@ -655,8 +649,28 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
             // Update formattedUrlString and urlTextBox.  It is necessary to do this after the page finishes loading because the final URL can change during load.
             @Override
             public void onPageFinished(WebView view, String url) {
-                // Check to see if we are waiting on Orbot.
-                if (pendingUrl.isEmpty()) {  // we are not waiting on Orbot, so we need to process the URL.
+                // Clear the cache and history if Incognito Mode is enabled.
+                if (incognitoModeEnabled) {
+                    // Clear the cache.  `true` includes disk files.
+                    mainWebView.clearCache(true);
+
+                    // Clear the back/forward history.
+                    mainWebView.clearHistory();
+
+                    // Manually delete cache folders.
+                    try {
+                        // Delete the main `cache` folder.
+                        privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache");
+
+                        // Delete the `app_webview` folder, which contains an additional `WebView` cache.  See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`.
+                        privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview");
+                    } catch (IOException e) {
+                        // Do nothing if an error is thrown.
+                    }
+                }
+
+                // Update `urlTextBox` and apply domain settings if not waiting on Orbot.
+                if (!waitingForOrbot) {
                     // Check to see if `WebView` has set `url` to be `about:blank`.
                     if (url.equals("about:blank")) {  // `WebView` is blank, so `formattedUrlString` should be `""` and `urlTextBox` should display a hint.
                         // Set `formattedUrlString` to `""`.
@@ -808,6 +822,12 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         // Hide zoom controls.
         mainWebView.getSettings().setDisplayZoomControls(false);
 
+        // Set `mainWebView` to use a wide viewport.  Otherwise, some web pages will be scrunched and some content will render outside the screen.
+        mainWebView.getSettings().setUseWideViewPort(true);
+
+        // Set `mainWebView` to load in overview mode (zoomed out to the maximum width).
+        mainWebView.getSettings().setLoadWithOverviewMode(true);
+
         // Initialize cookieManager.
         cookieManager = CookieManager.getInstance();
 
@@ -828,6 +848,12 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
             formattedUrlString = launchingIntentUriData.toString();
         }
 
+        // Get a handle for the `Runtime`.
+        privacyBrowserRuntime = Runtime.getRuntime();
+
+        // Store the application's private data directory.
+        privateDataDirectoryString = getApplicationInfo().dataDir;  // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`.
+
         // Initialize `inFullScreenBrowsingMode`, which is always false at this point because Privacy Browser never starts in full screen browsing mode.
         inFullScreenBrowsingMode = false;
 
@@ -844,9 +870,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         // Initialize `webViewTitle`.
         webViewTitle = getString(R.string.no_title);
 
-        // Apply the app settings from the shared preferences.
-        applyAppSettings();
-
         // Initialize `favoriteIconBitmap`.  We have to use `ContextCompat` until API >= 21.
         Drawable favoriteIconDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.world);
         BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable;
@@ -855,12 +878,15 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         // If the favorite icon is null, load the default.
         if (favoriteIconBitmap == null) {
             favoriteIconBitmap = favoriteIconDefaultBitmap;
+        }
 
-        // Load `formattedUrlString` if we are not proxying through Orbot and waiting for Orbot to connect.
-        if (!(proxyThroughOrbot && !orbotStatus.equals("ON"))) {
+        // Apply the app settings from the shared preferences.
+        applyAppSettings();
+
+        // Load `formattedUrlString` if we are not waiting for Orbot to connect.
+        if (!waitingForOrbot) {
             loadUrl(formattedUrlString);
         }
-        }
     }
 
 
@@ -964,6 +990,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
 
         // Prepare the font size title and current size menu item.
         switch (fontSize) {
+            case 25:
+                fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.twenty_five_percent);
+                selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeTwentyFivePercent);
+                break;
+
             case 50:
                 fontSizeTitle = getResources().getString(R.string.font_size) + " - " + getResources().getString(R.string.fifty_percent);
                 selectedFontSizeMenuItem = menu.findItem(R.id.fontSizeFiftyPercent);
@@ -1168,6 +1199,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 Snackbar.make(findViewById(R.id.main_webview), R.string.form_data_deleted, Snackbar.LENGTH_SHORT).show();
                 return true;
 
+            case R.id.fontSizeTwentyFivePercent:
+                mainWebView.getSettings().setTextZoom(25);
+                return true;
+
             case R.id.fontSizeFiftyPercent:
                 mainWebView.getSettings().setTextZoom(50);
                 return true;
@@ -1358,7 +1393,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 WebViewDatabase webViewDatabase = WebViewDatabase.getInstance(this);
                 webViewDatabase.clearFormData();
 
-                // Clear cache.  The argument of "true" includes disk files.
+                // Clear the cache.  `true` includes disk files.
                 mainWebView.clearCache(true);
 
                 // Clear the back/forward history.
@@ -1379,15 +1414,13 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 // Destroy the internal state of `mainWebView`.
                 mainWebView.destroy();
 
-                // Manually delete folders.
-                Runtime runtime = Runtime.getRuntime();
-                String dataDirString = getApplicationInfo().dataDir;  // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`.
+                // Manually delete cache folders.
                 try {
                     // Delete the main `cache` folder.
-                    runtime.exec("rm -rf " + dataDirString + "/cache");
+                    privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache");
 
                     // Delete the `app_webview` folder, which contains an additional `WebView` cache.  See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`.
-                    runtime.exec("rm -rf " + dataDirString + "/app_webview");
+                    privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview");
                 } catch (IOException e) {
                     // Do nothing if an error is thrown.
                 }
@@ -1801,7 +1834,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     }
 
     @Override
-    public void onResume() {
+    public void onResume() {  // `onResume()` also runs every time the app starts after `onCreate()` and `onStart()`.
         super.onResume();
 
         // Resume JavaScript (if enabled).
@@ -1833,7 +1866,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         String unformattedUrlString = urlTextBox.getText().toString().trim();
 
         // Check to see if `unformattedUrlString` is a valid URL.  Otherwise, convert it into a search.
-        if ((Patterns.WEB_URL.matcher(unformattedUrlString).matches()) || (unformattedUrlString.contains("localhost"))) {
+        if ((Patterns.WEB_URL.matcher(unformattedUrlString).matches()) || (unformattedUrlString.startsWith("http://")) || (unformattedUrlString.startsWith("https://"))) {
             // Add `http://` at the beginning if it is missing.  Otherwise the app will segfault.
             if (!unformattedUrlString.startsWith("http")) {
                 unformattedUrlString = "http://" + unformattedUrlString;
@@ -1866,12 +1899,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
             // Sanitize the search input and convert it to a search.
             final String encodedUrlString = URLEncoder.encode(unformattedUrlString, "UTF-8");
 
-            // Use the correct search URL.
-            if (javaScriptEnabled) {  // JavaScript is enabled.
-                formattedUrlString = javaScriptEnabledSearchURL + encodedUrlString;
-            } else { // JavaScript is disabled.
-                formattedUrlString = javaScriptDisabledSearchURL + encodedUrlString;
-            }
+            // Add the base search URL.
+            formattedUrlString = searchURL + encodedUrlString;
         }
 
         loadUrl(formattedUrlString);
@@ -2100,23 +2129,20 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
 
         // Store the values from `sharedPreferences` in variables.
-        String javaScriptDisabledSearchString = sharedPreferences.getString("javascript_disabled_search", "https://duckduckgo.com/html/?q=");
-        String javaScriptDisabledSearchCustomURLString = sharedPreferences.getString("javascript_disabled_search_custom_url", "");
-        String javaScriptEnabledSearchString = sharedPreferences.getString("javascript_enabled_search", "https://duckduckgo.com/?q=");
-        String javaScriptEnabledSearchCustomURLString = sharedPreferences.getString("javascript_enabled_search_custom_url", "");
         String homepageString = sharedPreferences.getString("homepage", "https://duckduckgo.com");
         String torHomepageString = sharedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion");
-        String torJavaScriptDisabledSearchString = sharedPreferences.getString("tor_javascript_disabled_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
-        String torJavaScriptDisabledSearchCustomURLString = sharedPreferences.getString("tor_javascript_disabled_search_custom_url", "");
-        String torJavaScriptEnabledSearchString = sharedPreferences.getString("tor_javascript_enabled_search", "https://3g2upl4pq6kufc4m.onion/?q=");
-        String torJavaScriptEnabledSearchCustomURLString = sharedPreferences.getString("tor_javascript_enabled_search_custom_url", "");
-        swipeToRefreshEnabled = sharedPreferences.getBoolean("swipe_to_refresh_enabled", false);
+        String torSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
+        String torSearchCustomURLString = sharedPreferences.getString("tor_search_custom_url", "");
+        String searchString = sharedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
+        String searchCustomURLString = sharedPreferences.getString("search_custom_url", "");
         adBlockerEnabled = sharedPreferences.getBoolean("block_ads", true);
+        incognitoModeEnabled = sharedPreferences.getBoolean("incognito_mode", false);
         boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", false);
-        proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
+        boolean proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
         fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("enable_full_screen_browsing_mode", false);
         hideSystemBarsOnFullscreen = sharedPreferences.getBoolean("hide_system_bars", false);
         translucentNavigationBarOnFullscreen = sharedPreferences.getBoolean("translucent_navigation_bar", true);
+        swipeToRefreshEnabled = sharedPreferences.getBoolean("swipe_to_refresh", false);
 
         // Set the homepage, search, and proxy options.
         if (proxyThroughOrbot) {  // Set the Tor options.
@@ -2128,18 +2154,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 formattedUrlString = homepage;
             }
 
-            // Set JavaScript disabled search.
-            if (torJavaScriptDisabledSearchString.equals("Custom URL")) {  // Get the custom URL string.
-                javaScriptDisabledSearchURL = torJavaScriptDisabledSearchCustomURLString;
-            } else {  // Use the string from the pre-built list.
-                javaScriptDisabledSearchURL = torJavaScriptDisabledSearchString;
-            }
-
-            // Set JavaScript enabled search.
-            if (torJavaScriptEnabledSearchString.equals("Custom URL")) {  // Get the custom URL string.
-                javaScriptEnabledSearchURL = torJavaScriptEnabledSearchCustomURLString;
+            // Set the search URL.
+            if (torSearchString.equals("Custom URL")) {  // Get the custom URL string.
+                searchURL = torSearchCustomURLString;
             } else {  // Use the string from the pre-built list.
-                javaScriptEnabledSearchURL = torJavaScriptEnabledSearchString;
+                searchURL = torSearchString;
             }
 
             // Set the proxy.  `this` refers to the current activity where an `AlertDialog` might be displayed.
@@ -2147,8 +2166,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
 
             // Display a message to the user if we are waiting on Orbot.
             if (!orbotStatus.equals("ON")) {
-                // Save `formattedUrlString` in `pendingUrl`.
-                pendingUrl = formattedUrlString;
+                // Set `waitingForOrbot`.
+                waitingForOrbot = true;
 
                 // Load a waiting page.  `null` specifies no encoding, which defaults to ASCII.
                 mainWebView.loadData(waitingForOrbotHTMLString, "text/html", null);
@@ -2162,28 +2181,18 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 formattedUrlString = homepage;
             }
 
-            // Set JavaScript disabled search.
-            if (javaScriptDisabledSearchString.equals("Custom URL")) {  // Get the custom URL string.
-                javaScriptDisabledSearchURL = javaScriptDisabledSearchCustomURLString;
+            // Set the search URL.
+            if (searchString.equals("Custom URL")) {  // Get the custom URL string.
+                searchURL = searchCustomURLString;
             } else {  // Use the string from the pre-built list.
-                javaScriptDisabledSearchURL = javaScriptDisabledSearchString;
-            }
-
-            // Set JavaScript enabled search.
-            if (javaScriptEnabledSearchString.equals("Custom URL")) {  // Get the custom URL string.
-                javaScriptEnabledSearchURL = javaScriptEnabledSearchCustomURLString;
-            } else {  // Use the string from the pre-built list.
-                javaScriptEnabledSearchURL = javaScriptEnabledSearchString;
+                searchURL = searchString;
             }
 
             // Reset the proxy to default.  The host is `""` and the port is `"0"`.
             OrbotProxyHelper.setProxy(getApplicationContext(), this, "", "0");
 
-            // Reset `pendingUrl` if we are currently waiting for Orbot to connect.
-            if (!pendingUrl.isEmpty()) {
-                formattedUrlString = pendingUrl;
-                pendingUrl = "";
-            }
+            // Reset `waitingForOrbot.
+            waitingForOrbot = false;
         }
 
         // Set swipe to refresh.
@@ -2229,8 +2238,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
             // Reset `inFullScreenBrowsingMode` to `false`.
             inFullScreenBrowsingMode = false;
 
-            // Show the `appBar`.
-            appBar.show();
+            // Show the `appBar` if `findOnPageLinearLayout` is not visible.
+            if (findOnPageLinearLayout.getVisibility() == View.GONE) {
+                appBar.show();
+            }
 
             // Show the `BannerAd` in the free flavor.
             if (BuildConfig.FLAVOR.contentEquals("free")) {