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=32d50e94c2d21d38548104f80287505c0ee5b0dd;hp=96380b3d9b90ed7724d73ef47caae82a49858782;hb=81179d84ced6b43360d42a4b44eb8fb329532ff4;hpb=75f7274fb8f3d161f632dc22daea406a881ffeb0 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 96380b3d..32d50e94 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -129,13 +129,16 @@ import com.stoutner.privacybrowser.dialogs.DownloadImageDialog; import com.stoutner.privacybrowser.dialogs.DownloadLocationPermissionDialog; import com.stoutner.privacybrowser.dialogs.EditBookmarkDialog; import com.stoutner.privacybrowser.dialogs.EditBookmarkFolderDialog; +import com.stoutner.privacybrowser.dialogs.FontSizeDialog; import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog; +import com.stoutner.privacybrowser.dialogs.ProxyNotInstalledDialog; import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog; import com.stoutner.privacybrowser.dialogs.SaveWebpageImageDialog; import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog; import com.stoutner.privacybrowser.dialogs.StoragePermissionDialog; import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog; import com.stoutner.privacybrowser.dialogs.ViewSslCertificateDialog; +import com.stoutner.privacybrowser.dialogs.WaitingForProxyDialog; import com.stoutner.privacybrowser.fragments.WebViewTabFragment; import com.stoutner.privacybrowser.helpers.AdHelper; import com.stoutner.privacybrowser.helpers.BlocklistHelper; @@ -143,7 +146,7 @@ import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; import com.stoutner.privacybrowser.helpers.CheckPinnedMismatchHelper; import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper; import com.stoutner.privacybrowser.helpers.FileNameHelper; -import com.stoutner.privacybrowser.helpers.OrbotProxyHelper; +import com.stoutner.privacybrowser.helpers.ProxyHelper; import com.stoutner.privacybrowser.views.NestedScrollWebView; import java.io.ByteArrayInputStream; @@ -161,16 +164,17 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; // AppCompatActivity from android.support.v7.app.AppCompatActivity must be used to have access to the SupportActionBar until the minimum API is >= 21. public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener, - EditBookmarkFolderDialog.EditBookmarkFolderListener, NavigationView.OnNavigationItemSelectedListener, PinnedMismatchDialog.PinnedMismatchListener, PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageImageDialog.SaveWebpageImageListener, + EditBookmarkFolderDialog.EditBookmarkFolderListener, FontSizeDialog.UpdateFontSizeListener, 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; + public static String orbotStatus = "unknown"; // The WebView pager adapter is accessed from `HttpAuthenticationDialog`, `PinnedMismatchDialog`, and `SslCertificateErrorDialog`. It is also used in `onCreate()`, `onResume()`, and `addTab()`. public static WebViewPagerAdapter webViewPagerAdapter; @@ -200,13 +204,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, - // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxyThroughOrbot()`, and `applyDomainSettings()`. + // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxy()`, and `applyDomainSettings()`. private NestedScrollWebView currentWebView; // `customHeader` is used in `onCreate()`, `onOptionsItemSelected()`, `onCreateContextMenu()`, and `loadUrl()`. private final Map customHeaders = new HashMap<>(); - // The search URL is set in `applyProxyThroughOrbot()` and used in `onCreate()`, `onNewIntent()`, `loadURLFromTextBox()`, and `initializeWebView()`. + // The search URL is set in `applyAppSettings()` and used in `onNewIntent()`, `loadUrlFromTextBox()`, `initializeApp()`, and `initializeWebView()`. private String searchURL; // The options menu is set in `onCreateOptionsMenu()` and used in `onOptionsItemSelected()`, `updatePrivacyIcons()`, and `initializeWebView()`. @@ -223,8 +227,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`. private String webViewDefaultUserAgent; - // `proxyThroughOrbot` is used in `onRestart()`, `onOptionsItemSelected()`, `applyAppSettings()`, and `applyProxyThroughOrbot()`. - private boolean proxyThroughOrbot; + // The proxy mode is used in `onRestart()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `applyAppSettings()`, and `applyProxy()`. + // It will be updated in `applyAppSettings()`, but it needs to be initialized here or the first run of `onPrepareOptionsMenu()` crashes. + private String proxyMode = ProxyHelper.NONE; // The incognito mode is set in `applyAppSettings()` and used in `initializeWebView()`. private boolean incognitoModeEnabled; @@ -254,8 +259,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`. private BroadcastReceiver orbotStatusBroadcastReceiver; - // `waitingForOrbot` is used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. - private boolean waitingForOrbot; + // The waiting for proxy boolean is used in `onResume()`, `initializeApp()` and `applyProxy()`. + private boolean waitingForProxy = false; // The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`. private ActionBarDrawerToggle actionBarDrawerToggle; @@ -441,7 +446,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook addNewTab(url, true); } else { // Load the URL in the current tab. // Make it so. - loadUrl(url); + loadUrl(currentWebView, url); } // Get a handle for the drawer layout. @@ -465,18 +470,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Run the default commands. super.onRestart(); - // Make sure Orbot is running if Privacy Browser is proxying through Orbot. - if (proxyThroughOrbot) { - // Request Orbot to start. If Orbot is already running no hard will be caused by this request. - Intent orbotIntent = new Intent("org.torproject.android.intent.action.START"); - - // Send the intent to the Orbot package. - orbotIntent.setPackage("org.torproject.android"); - - // Make it so. - sendBroadcast(orbotIntent); - } - // Apply the app settings if returning from the Settings activity. if (reapplyAppSettingsOnRestart) { // Reset the reapply app settings on restart tracker. @@ -518,7 +511,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Load the URL on restart (used when loading a bookmark). if (loadUrlOnRestart) { // Load the specified URL. - loadUrl(urlToLoadOnRestart); + loadUrl(currentWebView, urlToLoadOnRestart); // Reset the load on restart tracker. loadUrlOnRestart = false; @@ -549,6 +542,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Run the default commands. super.onResume(); + // Resume any WebViews. for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { // Get the WebView tab fragment. WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); @@ -569,16 +563,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // Display a message to the user if waiting for Orbot. - if (waitingForOrbot && !orbotStatus.equals("ON")) { - // Disable the wide view port so that the waiting for Orbot text is displayed correctly. - currentWebView.getSettings().setUseWideViewPort(false); - - // Load a waiting page. `null` specifies no encoding, which defaults to ASCII. - currentWebView.loadData("

" + getString(R.string.waiting_for_orbot) + "

", "text/html", null); + // Reapply the proxy settings if the system is using a proxy. This redisplays the appropriate alert dialog. + if (!proxyMode.equals(ProxyHelper.NONE)) { + applyProxy(false); } - if (displayingFullScreenVideo || inFullScreenBrowsingMode) { + // Reapply any system UI flags and the ad in the free flavor. + if (displayingFullScreenVideo || inFullScreenBrowsingMode) { // The system is displaying a website or a video in full screen mode. // Get a handle for the root frame layouts. FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout); @@ -593,7 +584,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook */ rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } else if (BuildConfig.FLAVOR.contentEquals("free")) { // Resume the adView for the free flavor. + } else if (BuildConfig.FLAVOR.contentEquals("free")) { // The system in not in full screen mode. // Resume the ad. AdHelper.resumeAd(findViewById(R.id.adview)); } @@ -633,7 +624,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override public void onDestroy() { - // Unregister the Orbot status broadcast receiver. + // Unregister the orbot status broadcast receiver. this.unregisterReceiver(orbotStatusBroadcastReceiver); // Close the bookmarks cursor and database. @@ -734,12 +725,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem ultraListMenuItem = menu.findItem(R.id.ultralist); MenuItem ultraPrivacyMenuItem = menu.findItem(R.id.ultraprivacy); MenuItem blockAllThirdPartyRequestsMenuItem = menu.findItem(R.id.block_all_third_party_requests); + MenuItem proxyMenuItem = menu.findItem(R.id.proxy); + MenuItem userAgentMenuItem = menu.findItem(R.id.user_agent); MenuItem fontSizeMenuItem = menu.findItem(R.id.font_size); MenuItem swipeToRefreshMenuItem = menu.findItem(R.id.swipe_to_refresh); MenuItem wideViewportMenuItem = menu.findItem(R.id.wide_viewport); MenuItem displayImagesMenuItem = menu.findItem(R.id.display_images); MenuItem nightModeMenuItem = menu.findItem(R.id.night_mode); - MenuItem proxyThroughOrbotMenuItem = menu.findItem(R.id.proxy_through_orbot); // Get a handle for the cookie manager. CookieManager cookieManager = CookieManager.getInstance(); @@ -801,9 +793,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook domStorageMenuItem.setEnabled(currentWebView.getSettings().getJavaScriptEnabled()); } - // Set the status of the menu item checkboxes. + // Set the checked status of the first party cookies menu item. firstPartyCookiesMenuItem.setChecked(cookieManager.acceptCookie()); - proxyThroughOrbotMenuItem.setChecked(proxyThroughOrbot); // Enable Clear Cookies if there are any. clearCookiesMenuItem.setEnabled(cookieManager.hasCookies()); @@ -815,14 +806,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook File localStorageDirectory = new File (privateDataDirectoryString + "/app_webview/Local Storage/"); int localStorageDirectoryNumberOfFiles = 0; if (localStorageDirectory.exists()) { - localStorageDirectoryNumberOfFiles = localStorageDirectory.list().length; + // `Objects.requireNonNull` removes a lint warning that `localStorageDirectory.list` might produce a null pointed exception if it is dereferenced. + localStorageDirectoryNumberOfFiles = Objects.requireNonNull(localStorageDirectory.list()).length; } // Get a count of the number of files in the IndexedDB directory. File indexedDBDirectory = new File (privateDataDirectoryString + "/app_webview/IndexedDB"); int indexedDBDirectoryNumberOfFiles = 0; if (indexedDBDirectory.exists()) { - indexedDBDirectoryNumberOfFiles = indexedDBDirectory.list().length; + // `Objects.requireNonNull` removes a lint warning that `indexedDBDirectory.list` might produce a null pointed exception if it is dereferenced. + indexedDBDirectoryNumberOfFiles = Objects.requireNonNull(indexedDBDirectory.list()).length; } // Enable Clear DOM Storage if there is any. @@ -843,91 +836,124 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Disable Fanboy's Social Blocking List menu item if Fanboy's Annoyance List is checked. fanboysSocialBlockingListMenuItem.setEnabled(!fanboysAnnoyanceListMenuItem.isChecked()); + // Set the proxy title and check the applied proxy. + switch (proxyMode) { + case ProxyHelper.NONE: + // Set the proxy title. + proxyMenuItem.setTitle(getString(R.string.proxy) + " - " + getString(R.string.proxy_none)); + + // Check the proxy None radio button. + menu.findItem(R.id.proxy_none).setChecked(true); + break; + + case ProxyHelper.TOR: + // Set the proxy title. + proxyMenuItem.setTitle(getString(R.string.proxy) + " - " + getString(R.string.proxy_tor)); + + // Check the proxy Tor radio button. + menu.findItem(R.id.proxy_tor).setChecked(true); + break; + + case ProxyHelper.I2P: + // Set the proxy title. + proxyMenuItem.setTitle(getString(R.string.proxy) + " - " + getString(R.string.proxy_i2p)); + + // Check the proxy I2P radio button. + menu.findItem(R.id.proxy_i2p).setChecked(true); + break; + + case ProxyHelper.CUSTOM: + // Set the proxy title. + proxyMenuItem.setTitle(getString(R.string.proxy) + " - " + getString(R.string.proxy_custom)); + + // Check the proxy Custom radio button. + menu.findItem(R.id.proxy_custom).setChecked(true); + break; + } + // Select the current user agent menu item. A switch statement cannot be used because the user agents are not compile time constants. if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[0])) { // Privacy Browser. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_privacy_browser)); + + // Select the Privacy Browser radio box. menu.findItem(R.id.user_agent_privacy_browser).setChecked(true); } else if (currentUserAgent.equals(webViewDefaultUserAgent)) { // WebView Default. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_webview_default)); + + // Select the WebView Default radio box. menu.findItem(R.id.user_agent_webview_default).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[2])) { // Firefox on Android. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_firefox_on_android)); + + // Select the Firefox on Android radio box. menu.findItem(R.id.user_agent_firefox_on_android).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[3])) { // Chrome on Android. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_chrome_on_android)); + + // Select the Chrome on Android radio box. menu.findItem(R.id.user_agent_chrome_on_android).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[4])) { // Safari on iOS. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_safari_on_ios)); + + // Select the Safari on iOS radio box. menu.findItem(R.id.user_agent_safari_on_ios).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[5])) { // Firefox on Linux. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_firefox_on_linux)); + + // Select the Firefox on Linux radio box. menu.findItem(R.id.user_agent_firefox_on_linux).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[6])) { // Chromium on Linux. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_chromium_on_linux)); + + // Select the Chromium on Linux radio box. menu.findItem(R.id.user_agent_chromium_on_linux).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[7])) { // Firefox on Windows. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_firefox_on_windows)); + + // Select the Firefox on Windows radio box. menu.findItem(R.id.user_agent_firefox_on_windows).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[8])) { // Chrome on Windows. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_chrome_on_windows)); + + // Select the Chrome on Windows radio box. menu.findItem(R.id.user_agent_chrome_on_windows).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[9])) { // Edge on Windows. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_edge_on_windows)); + + // Select the Edge on Windows radio box. menu.findItem(R.id.user_agent_edge_on_windows).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[10])) { // Internet Explorer on Windows. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_internet_explorer_on_windows)); + + // Select the Internet on Windows radio box. menu.findItem(R.id.user_agent_internet_explorer_on_windows).setChecked(true); } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[11])) { // Safari on macOS. + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_safari_on_macos)); + + // Select the Safari on macOS radio box. menu.findItem(R.id.user_agent_safari_on_macos).setChecked(true); } else { // Custom user agent. - menu.findItem(R.id.user_agent_custom).setChecked(true); - } - - // Instantiate the font size title and the selected font size menu item. - String fontSizeTitle; - MenuItem selectedFontSizeMenuItem; - - // Prepare the font size title and current size menu item. - //noinspection DuplicateBranchesInSwitch - switch (fontSize) { - case 25: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.twenty_five_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_twenty_five_percent); - break; - - case 50: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.fifty_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_fifty_percent); - break; + // Update the user agent menu item title. + userAgentMenuItem.setTitle(getString(R.string.user_agent) + " - " + getString(R.string.user_agent_custom)); - case 75: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.seventy_five_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_seventy_five_percent); - break; - - case 100: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_percent); - break; - - case 125: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_twenty_five_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_twenty_five_percent); - break; - - case 150: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_fifty_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_fifty_percent); - break; - - case 175: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_seventy_five_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_seventy_five_percent); - break; - - case 200: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.two_hundred_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_two_hundred_percent); - break; - - default: - fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_percent); - selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_percent); - break; + // Select the Custom radio box. + menu.findItem(R.id.user_agent_custom).setChecked(true); } - // Set the font size title and select the current size menu item. - fontSizeMenuItem.setTitle(fontSizeTitle); - selectedFontSizeMenuItem.setChecked(true); + // Set the font size title. + fontSizeMenuItem.setTitle(getString(R.string.font_size) + " - " + fontSize + "%"); // Run all the other default commands. super.onPrepareOptionsMenu(menu); @@ -1376,6 +1402,46 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; + case R.id.proxy_none: + // Update the proxy mode. + proxyMode = ProxyHelper.NONE; + + // Apply the proxy mode. + applyProxy(true); + + // Consume the event. + return true; + + case R.id.proxy_tor: + // Update the proxy mode. + proxyMode = ProxyHelper.TOR; + + // Apply the proxy mode. + applyProxy(true); + + // Consume the event. + return true; + + case R.id.proxy_i2p: + // Update the proxy mode. + proxyMode = ProxyHelper.I2P; + + // Apply the proxy mode. + applyProxy(true); + + // Consume the event. + return true; + + case R.id.proxy_custom: + // Update the proxy mode. + proxyMode = ProxyHelper.CUSTOM; + + // Apply the proxy mode. + applyProxy(true); + + // Consume the event. + return true; + case R.id.user_agent_privacy_browser: // Update the user agent. currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[0]); @@ -1506,58 +1572,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; - case R.id.font_size_twenty_five_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(25); - - // Consume the event. - return true; - - case R.id.font_size_fifty_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(50); - - // Consume the event. - return true; + case R.id.font_size: + // Instantiate the font size dialog. + DialogFragment fontSizeDialogFragment = FontSizeDialog.displayDialog(currentWebView.getSettings().getTextZoom()); - case R.id.font_size_seventy_five_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(75); - - // Consume the event. - return true; - - case R.id.font_size_one_hundred_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(100); - - // Consume the event. - return true; - - case R.id.font_size_one_hundred_twenty_five_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(125); - - // Consume the event. - return true; - - case R.id.font_size_one_hundred_fifty_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(150); - - // Consume the event. - return true; - - case R.id.font_size_one_hundred_seventy_five_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(175); - - // Consume the event. - return true; - - case R.id.font_size_two_hundred_percent: - // Set the font size. - currentWebView.getSettings().setTextZoom(200); + // Show the font size dialog. + fontSizeDialogFragment.show(getSupportFragmentManager(), getString(R.string.font_size)); // Consume the event. return true; @@ -1742,16 +1762,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; - case R.id.proxy_through_orbot: - // Toggle the proxy through Orbot variable. - proxyThroughOrbot = !proxyThroughOrbot; - - // Apply the proxy through Orbot settings. - applyProxyThroughOrbot(true); - - // Consume the event. - return true; - case R.id.refresh: if (menuItem.getTitle().equals(getString(R.string.refresh))) { // The refresh button was pushed. // Reload the current WebView. @@ -1797,14 +1807,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook break; case R.id.home: - // Select the homepage based on the proxy through Orbot status. - if (proxyThroughOrbot) { - // Load the Tor homepage. - loadUrl(sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value))); - } else { - // Load the normal homepage. - loadUrl(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value))); - } + // Load the homepage. + loadUrl(currentWebView, sharedPreferences.getString("homepage", getString(R.string.homepage_default_value))); break; case R.id.back: @@ -2183,7 +2187,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a View Image entry. menu.add(R.string.view_image).setOnMenuItemClickListener(item -> { // Load the image in the current tab. - loadUrl(imageUrl); + loadUrl(currentWebView, imageUrl); // Consume the event. return true; @@ -2308,7 +2312,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a View Image entry. menu.add(R.string.view_image).setOnMenuItemClickListener((MenuItem item) -> { // View the image in the current tab. - loadUrl(imageUrl); + loadUrl(currentWebView, imageUrl); // Consume the event. return true; @@ -3051,18 +3055,18 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook urlEditText.clearFocus(); // Make it so. - loadUrl(url); + loadUrl(currentWebView, url); } - private void loadUrl(String url) { + private void loadUrl(NestedScrollWebView nestedScrollWebView, String url) { // Sanitize the URL. url = sanitizeUrl(url); // Apply the domain settings. - applyDomainSettings(currentWebView, url, true, false); + applyDomainSettings(nestedScrollWebView, url, true, false); // Load the URL. - currentWebView.loadUrl(url, customHeaders); + nestedScrollWebView.loadUrl(url, customHeaders); } public void findPreviousOnPage(View view) { @@ -3105,6 +3109,31 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook inputMethodManager.hideSoftInputFromWindow(toolbar.getWindowToken(), 0); } + @Override + public void onApplyNewFontSize(DialogFragment dialogFragment) { + // Get the dialog. + Dialog dialog = dialogFragment.getDialog(); + + // Remove the incorrect lint warning below tha the dialog might be null. + assert dialog != null; + + // Get a handle for the font size edit text. + EditText fontSizeEditText = dialog.findViewById(R.id.font_size_edittext); + + // Initialize the new font size variable with the current font size. + int newFontSize = currentWebView.getSettings().getTextZoom(); + + // Get the font size from the edit text. + try { + newFontSize = Integer.valueOf(fontSizeEditText.getText().toString()); + } catch (Exception exception) { + // If the edit text does not contain a valid font size do nothing. + } + + // Apply the new font size. + currentWebView.getSettings().setTextZoom(newFontSize); + } + @Override public void onSaveWebpageImage(DialogFragment dialogFragment) { // Get the dialog. @@ -3174,11 +3203,21 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook sanitizeGoogleAnalytics = sharedPreferences.getBoolean("google_analytics", true); sanitizeFacebookClickIds = sharedPreferences.getBoolean("facebook_click_ids", true); sanitizeTwitterAmpRedirects = sharedPreferences.getBoolean("twitter_amp_redirects", true); - proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false); + proxyMode = sharedPreferences.getString("proxy", getString(R.string.proxy_default_value)); fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false); hideAppBar = sharedPreferences.getBoolean("hide_app_bar", true); scrollAppBar = sharedPreferences.getBoolean("scroll_app_bar", true); + // Get the search string. + String searchString = sharedPreferences.getString("search", getString(R.string.search_default_value)); + + // Set the search string. + if (searchString.equals("Custom URL")) { // A custom search string is used. + searchURL = sharedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value)); + } else { // A custom search string is not used. + searchURL = searchString; + } + // Get handles for the views that need to be modified. FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout); AppBarLayout appBarLayout = findViewById(R.id.appbar_layout); @@ -3191,8 +3230,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Remove the incorrect lint warning below that the action bar might be null. assert actionBar != null; - // Apply the proxy through Orbot settings. - applyProxyThroughOrbot(false); + // Apply the proxy. + applyProxy(false); // Set Do Not Track status. if (doNotTrackEnabled) { @@ -3358,61 +3397,57 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); - // Initialize the Orbot status and the waiting for Orbot trackers. - orbotStatus = "unknown"; - waitingForOrbot = false; - - // Create an Orbot status `BroadcastReceiver`. + // Create an Orbot status broadcast receiver. orbotStatusBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Store the content of the status message in `orbotStatus`. orbotStatus = intent.getStringExtra("org.torproject.android.intent.extra.STATUS"); - // If Privacy Browser is waiting on Orbot, load the website now that Orbot is connected. - if (orbotStatus.equals("ON") && waitingForOrbot) { - // Reset the waiting for Orbot status. - waitingForOrbot = false; + // If Privacy Browser is waiting on the proxy, load the website now that Orbot is connected. + if ((orbotStatus != null) && orbotStatus.equals("ON") && waitingForProxy) { + // Reset the waiting for proxy status. + waitingForProxy = false; - // Get the intent that started the app. - Intent launchingIntent = getIntent(); + // Get a handle for the waiting for proxy dialog. + DialogFragment waitingForProxyDialogFragment = (DialogFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.waiting_for_proxy_dialog)); - // Get the information from the intent. - String launchingIntentAction = launchingIntent.getAction(); - Uri launchingIntentUriData = launchingIntent.getData(); + // Dismiss the waiting for proxy dialog if it is displayed. + if (waitingForProxyDialogFragment != null) { + waitingForProxyDialogFragment.dismiss(); + } - // 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; + // Load any URLs that are waiting for the proxy. + for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); - // Sanitize the search input and convert it to a search. - try { - encodedUrlString = URLEncoder.encode(launchingIntent.getStringExtra(SearchManager.QUERY), "UTF-8"); - } catch (UnsupportedEncodingException exception) { - encodedUrlString = ""; - } + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); - // Load the completed search URL. - loadUrl(searchURL + encodedUrlString); - } else if (launchingIntentUriData != null){ // Check to see if the intent contains a new URL. - // Load the URL from the intent. - loadUrl(launchingIntentUriData.toString()); - } else { // The is no URL in the intent. - // Select the homepage based on the proxy through Orbot status. - if (proxyThroughOrbot) { - // Load the Tor homepage. - loadUrl(sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value))); - } else { - // Load the normal homepage. - loadUrl(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value))); + // Only process the WebViews if they exist. + if (fragmentView != null) { + // Get the nested scroll WebView from the tab fragment. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Get the waiting for proxy URL string. + String waitingForProxyUrlString = nestedScrollWebView.getWaitingForProxyUrlString(); + + // Load the pending URL if it exists. + if (!waitingForProxyUrlString.isEmpty()) { + // Load the URL. + loadUrl(nestedScrollWebView, waitingForProxyUrlString); + + // Reset the waiting for proxy URL string. + nestedScrollWebView.resetWaitingForProxyUrlString(); + } } } } } }; - // Register `orbotStatusBroadcastReceiver` on `this` context. + // Register the Orbot status broadcast receiver on `this` context. this.registerReceiver(orbotStatusBroadcastReceiver, new IntentFilter("org.torproject.android.intent.action.STATUS")); // Get handles for views that need to be modified. @@ -3627,10 +3662,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook bookmarksListView.setOnItemClickListener((parent, view, position, id) -> { // Convert the id from long to int to match the format of the bookmarks database. - int databaseID = (int) id; + int databaseId = (int) id; + + // Get the bookmark cursor for this ID. + Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseId); - // Get the bookmark cursor for this ID and move it to the first row. - Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseID); + // Move the bookmark cursor to the first row. bookmarkCursor.moveToFirst(); // Act upon the bookmark according to the type. @@ -3642,7 +3679,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook loadBookmarksFolder(); } else { // The selected bookmark is not a folder. // Load the bookmark URL. - loadUrl(bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL))); + loadUrl(currentWebView, bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL))); // Close the bookmarks drawer. drawerLayout.closeDrawer(GravityCompat.END); @@ -3663,13 +3700,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Save the current folder name, which is used in `onSaveEditBookmarkFolder()`. oldFolderNameString = bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); - // Show the edit bookmark folder `AlertDialog` and name the instance `@string/edit_folder`. + // Instantiate the edit folder bookmark dialog. DialogFragment editBookmarkFolderDialog = EditBookmarkFolderDialog.folderDatabaseId(databaseId, currentWebView.getFavoriteOrDefaultIcon()); + + // Show the edit folder bookmark dialog. editBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.edit_folder)); } else { - // Show the edit bookmark `AlertDialog` and name the instance `@string/edit_bookmark`. - DialogFragment editBookmarkDialog = EditBookmarkDialog.bookmarkDatabaseId(databaseId, currentWebView.getFavoriteOrDefaultIcon()); - editBookmarkDialog.show(getSupportFragmentManager(), getString(R.string.edit_bookmark)); + // Get the bookmark cursor for this ID. + Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseId); + + // Move the bookmark cursor to the first row. + bookmarkCursor.moveToFirst(); + + // Load the bookmark in a new tab but do not switch to the tab or close the drawer. + addNewTab(bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)), false); } // Consume the event. @@ -4034,10 +4078,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Apply the font size. - if (fontSize == 0) { // Apply the default font size. - nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); - } else { // Apply the specified font size. - nestedScrollWebView.getSettings().setTextZoom(fontSize); + try { // Try the specified font size to see if it is valid. + if (fontSize == 0) { // Apply the default font size. + // Try to set the font size from the value in the app settings. + nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); + } else { // Apply the font size from domain settings. + nestedScrollWebView.getSettings().setTextZoom(fontSize); + } + } catch (Exception exception) { // The specified font size is invalid + // Set the font size to be 100% + nestedScrollWebView.getSettings().setTextZoom(100); } // Set the user agent. @@ -4173,9 +4223,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.getSettings().setJavaScriptEnabled(defaultJavaScriptEnabled); } - // Apply the default settings. + // Apply the default first-party cookie setting. cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies()); - nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); + + // Apply the default font size setting. + try { + // Try to set the font size from the value in the app settings. + nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString)); + } catch (Exception exception) { + // If the app settings value is invalid, set the font size to 100%. + nestedScrollWebView.getSettings().setTextZoom(100); + } // Apply the form data setting if the API < 26. if (Build.VERSION.SDK_INT < 26) { @@ -4247,92 +4305,129 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return !nestedScrollWebView.getSettings().getUserAgentString().equals(initialUserAgent); } - private void applyProxyThroughOrbot(boolean reloadWebsite) { + private void applyProxy(boolean reloadWebViews) { // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - // Get the search and theme preferences. - String torSearchString = sharedPreferences.getString("tor_search", getString(R.string.tor_search_default_value)); - String torSearchCustomUrlString = sharedPreferences.getString("tor_search_custom_url", getString(R.string.tor_search_custom_url_default_value)); - String searchString = sharedPreferences.getString("search", getString(R.string.search_default_value)); - String searchCustomUrlString = sharedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value)); + // Get the theme preferences. boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false); // Get a handle for the app bar layout. AppBarLayout appBarLayout = findViewById(R.id.appbar_layout); - // Set the homepage, search, and proxy options. - if (proxyThroughOrbot) { // Set the Tor options. - // 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. - searchURL = torSearchString; - } + // Set the proxy according to the mode. `this` refers to the current activity where an alert dialog might be displayed. + ProxyHelper.setProxy(getApplicationContext(), proxyMode); - // Set the proxy. `this` refers to the current activity where an `AlertDialog` might be displayed. - OrbotProxyHelper.setProxy(getApplicationContext(), this, "localhost", "8118"); + // Reset the waiting for proxy tracker. + waitingForProxy = false; - // Set the app bar background to indicate proxying through Orbot is enabled. - if (darkTheme) { - appBarLayout.setBackgroundResource(R.color.dark_blue_30); - } else { - appBarLayout.setBackgroundResource(R.color.blue_50); - } + // Update the user interface and reload the WebViews is requested. + switch (proxyMode) { + case ProxyHelper.NONE: + // Set the default app bar layout background. + if (darkTheme) { + appBarLayout.setBackgroundResource(R.color.gray_900); + } else { + appBarLayout.setBackgroundResource(R.color.gray_100); + } + break; - // Check to see if Orbot is ready. - if (!orbotStatus.equals("ON")) { // Orbot is not ready. - // Set `waitingForOrbot`. - waitingForOrbot = true; + case ProxyHelper.TOR: + // Set the app bar background to indicate proxying through Orbot is enabled. + if (darkTheme) { + appBarLayout.setBackgroundResource(R.color.dark_blue_30); + } else { + appBarLayout.setBackgroundResource(R.color.blue_50); + } - // Disable the wide view port so that the waiting for Orbot text is displayed correctly. - currentWebView.getSettings().setUseWideViewPort(false); + // Check to see if Orbot is installed. + try { + // Get the package manager. + PackageManager packageManager = getPackageManager(); - // Load a waiting page. `null` specifies no encoding, which defaults to ASCII. - currentWebView.loadData("

" + getString(R.string.waiting_for_orbot) + "

", "text/html", null); - } else if (reloadWebsite) { // Orbot is ready and the website should be reloaded. - // Reload the website. - currentWebView.reload(); - } - } else { // Set the non-Tor options. - // 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. - searchURL = searchString; - } + // Check to see if Orbot is in the list. This will throw an error and drop to the catch section if it isn't installed. + packageManager.getPackageInfo("org.torproject.android", 0); - // Reset the proxy to default. The host is `""` and the port is `"0"`. - OrbotProxyHelper.setProxy(getApplicationContext(), this, "", "0"); + // Check to see if the proxy is ready. + if (!orbotStatus.equals("ON")) { // Orbot is not ready. + // Set the waiting for proxy status. + waitingForProxy = true; - // Set the default app bar layout background. - if (darkTheme) { - appBarLayout.setBackgroundResource(R.color.gray_900); - } else { - appBarLayout.setBackgroundResource(R.color.gray_100); - } + // Show the waiting for proxy dialog if it isn't already displayed. + if (getSupportFragmentManager().findFragmentByTag(getString(R.string.waiting_for_proxy_dialog)) == null) { + // Get a handle for the waiting for proxy alert dialog. + DialogFragment waitingForProxyDialogFragment = new WaitingForProxyDialog(); - // Reset `waitingForOrbot. - waitingForOrbot = false; + // Display the waiting for proxy alert dialog. + waitingForProxyDialogFragment.show(getSupportFragmentManager(), getString(R.string.waiting_for_proxy_dialog)); + } + } + } catch (PackageManager.NameNotFoundException exception) { // Orbot is not installed. + // Show the Orbot not installed dialog if it is not already displayed. + if (getSupportFragmentManager().findFragmentByTag(getString(R.string.proxy_not_installed_dialog)) == null) { + // Get a handle for the Orbot not installed alert dialog. + DialogFragment orbotNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode); + + // Display the Orbot not installed alert dialog. + orbotNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog)); + } + } + break; - // Reload the WebViews if requested. - if (reloadWebsite) { - // Reload the WebViews. - for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { - // Get the WebView tab fragment. - WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); + case ProxyHelper.I2P: + // Set the app bar background to indicate proxying through Orbot is enabled. + if (darkTheme) { + appBarLayout.setBackgroundResource(R.color.dark_blue_30); + } else { + appBarLayout.setBackgroundResource(R.color.blue_50); + } - // Get the fragment view. - View fragmentView = webViewTabFragment.getView(); + // Check to see if I2P is installed. + try { + // Get the package manager. + PackageManager packageManager = getPackageManager(); + + // Check to see if I2P is in the list. This will throw an error and drop to the catch section if it isn't installed. + packageManager.getPackageInfo("org.torproject.android", 0); + } catch (PackageManager.NameNotFoundException exception) { // I2P is not installed. + // Sow the I2P not installed dialog if it is not already displayed. + if (getSupportFragmentManager().findFragmentByTag(getString(R.string.proxy_not_installed_dialog)) == null) { + // Get a handle for the waiting for proxy alert dialog. + DialogFragment i2pNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode); + + // Display the I2P not installed alert dialog. + i2pNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog)); + } + } + break; - // Only reload the WebViews if they exist. - if (fragmentView != null) { - // Get the nested scroll WebView from the tab fragment. - NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + case ProxyHelper.CUSTOM: + // Set the app bar background to indicate proxying through Orbot is enabled. + if (darkTheme) { + appBarLayout.setBackgroundResource(R.color.dark_blue_30); + } else { + appBarLayout.setBackgroundResource(R.color.blue_50); + } + break; + } - // Reload the WebView. - nestedScrollWebView.reload(); - } + // Reload the WebViews if requested and not waiting for the proxy. + if (reloadWebViews && !waitingForProxy) { + // Reload the WebViews. + for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); + + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Only reload the WebViews if they exist. + if (fragmentView != null) { + // Get the nested scroll WebView from the tab fragment. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Reload the WebView. + nestedScrollWebView.reload(); } } } @@ -5964,50 +6059,47 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Hide the keyboard. inputMethodManager.hideSoftInputFromWindow(nestedScrollWebView.getWindowToken(), 0); - // Check to see if Privacy Browser is waiting on Orbot. - if (!waitingForOrbot) { // Process the URL. - // Get the current page position. - int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); + // Get the current page position. + int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); - // Update the URL text bar if the page is currently selected. - if (tabLayout.getSelectedTabPosition() == currentPagePosition) { - // Clear the focus from the URL edit text. - urlEditText.clearFocus(); + // Update the URL text bar if the page is currently selected. + if (tabLayout.getSelectedTabPosition() == currentPagePosition) { + // Clear the focus from the URL edit text. + urlEditText.clearFocus(); - // Display the formatted URL text. - urlEditText.setText(url); + // Display the formatted URL text. + urlEditText.setText(url); - // Apply text highlighting to `urlTextBox`. - highlightUrlText(); - } + // Apply text highlighting to `urlTextBox`. + highlightUrlText(); + } - // Reset the list of host IP addresses. - nestedScrollWebView.clearCurrentIpAddresses(); + // Reset the list of host IP addresses. + nestedScrollWebView.clearCurrentIpAddresses(); - // Get a URI for the current URL. - Uri currentUri = Uri.parse(url); + // Get a URI for the current URL. + Uri currentUri = Uri.parse(url); - // Get the IP addresses for the host. - new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost()); + // Get the IP addresses for the host. + new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost()); - // 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. - MenuItem refreshMenuItem = optionsMenu.findItem(R.id.refresh); + // 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. + MenuItem refreshMenuItem = optionsMenu.findItem(R.id.refresh); - // Set the title. - refreshMenuItem.setTitle(R.string.stop); + // Set the title. + refreshMenuItem.setTitle(R.string.stop); - // Get the app bar and theme preferences. - boolean displayAdditionalAppBarIcons = sharedPreferences.getBoolean("display_additional_app_bar_icons", false); + // Get the app bar and theme preferences. + boolean displayAdditionalAppBarIcons = sharedPreferences.getBoolean("display_additional_app_bar_icons", false); - // If the icon is displayed in the AppBar, set it according to the theme. - if (displayAdditionalAppBarIcons) { - if (darkTheme) { - refreshMenuItem.setIcon(R.drawable.close_dark); - } else { - refreshMenuItem.setIcon(R.drawable.close_light); - } + // If the icon is displayed in the AppBar, set it according to the theme. + if (displayAdditionalAppBarIcons) { + if (darkTheme) { + refreshMenuItem.setIcon(R.drawable.close_dark); + } else { + refreshMenuItem.setIcon(R.drawable.close_light); } } } @@ -6067,82 +6159,79 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // Update the URL text box and apply domain settings if not waiting on Orbot. - if (!waitingForOrbot) { - // Get the current page position. - int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); + // Get the current page position. + int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); - // Check the current website information against any pinned domain information if the current IP addresses have been loaded. - if ((nestedScrollWebView.hasPinnedSslCertificate() || nestedScrollWebView.hasPinnedIpAddresses()) && nestedScrollWebView.hasCurrentIpAddresses() && - !nestedScrollWebView.ignorePinnedDomainInformation()) { - CheckPinnedMismatchHelper.checkPinnedMismatch(getSupportFragmentManager(), nestedScrollWebView); - } + // Check the current website information against any pinned domain information if the current IP addresses have been loaded. + if ((nestedScrollWebView.hasPinnedSslCertificate() || nestedScrollWebView.hasPinnedIpAddresses()) && nestedScrollWebView.hasCurrentIpAddresses() && + !nestedScrollWebView.ignorePinnedDomainInformation()) { + CheckPinnedMismatchHelper.checkPinnedMismatch(getSupportFragmentManager(), nestedScrollWebView); + } - // Get the current URL from the nested scroll WebView. This is more accurate than using the URL passed into the method, which is sometimes not the final one. - String currentUrl = nestedScrollWebView.getUrl(); + // Get the current URL from the nested scroll WebView. This is more accurate than using the URL passed into the method, which is sometimes not the final one. + String currentUrl = nestedScrollWebView.getUrl(); - // Get the current tab. - TabLayout.Tab tab = tabLayout.getTabAt(currentPagePosition); + // Get the current tab. + TabLayout.Tab tab = tabLayout.getTabAt(currentPagePosition); - // Update the URL text bar if the page is currently selected and the user is not currently typing in the URL edit text. - // Crash records show that, in some crazy way, it is possible for the current URL to be blank at this point. - // Probably some sort of race condition when Privacy Browser is being resumed. - if ((tabLayout.getSelectedTabPosition() == currentPagePosition) && !urlEditText.hasFocus() && (currentUrl != null)) { - // Check to see if the URL is `about:blank`. - if (currentUrl.equals("about:blank")) { // The WebView is blank. - // Display the hint in the URL edit text. - urlEditText.setText(""); + // Update the URL text bar if the page is currently selected and the user is not currently typing in the URL edit text. + // Crash records show that, in some crazy way, it is possible for the current URL to be blank at this point. + // Probably some sort of race condition when Privacy Browser is being resumed. + if ((tabLayout.getSelectedTabPosition() == currentPagePosition) && !urlEditText.hasFocus() && (currentUrl != null)) { + // Check to see if the URL is `about:blank`. + if (currentUrl.equals("about:blank")) { // The WebView is blank. + // Display the hint in the URL edit text. + urlEditText.setText(""); - // Request focus for the URL text box. - urlEditText.requestFocus(); + // Request focus for the URL text box. + urlEditText.requestFocus(); - // Display the keyboard. - inputMethodManager.showSoftInput(urlEditText, 0); + // Display the keyboard. + inputMethodManager.showSoftInput(urlEditText, 0); - // Apply the domain settings. This clears any settings from the previous domain. - applyDomainSettings(nestedScrollWebView, "", true, false); + // Apply the domain settings. This clears any settings from the previous domain. + applyDomainSettings(nestedScrollWebView, "", true, false); - // Only populate the title text view if the tab has been fully created. - if (tab != null) { - // Get the custom view from the tab. - View tabView = tab.getCustomView(); + // Only populate the title text view if the tab has been fully created. + if (tab != null) { + // Get the custom view from the tab. + View tabView = tab.getCustomView(); - // Remove the incorrect warning below that the current tab view might be null. - assert tabView != null; + // Remove the incorrect warning below that the current tab view might be null. + assert tabView != null; - // Get the title text view from the tab. - TextView tabTitleTextView = tabView.findViewById(R.id.title_textview); + // Get the title text view from the tab. + TextView tabTitleTextView = tabView.findViewById(R.id.title_textview); - // Set the title as the tab text. - tabTitleTextView.setText(R.string.new_tab); - } - } else { // The WebView has loaded a webpage. - // Update the URL edit text if it is not currently being edited. - if (!urlEditText.hasFocus()) { - // Sanitize the current URL. This removes unwanted URL elements that were added by redirects, so that they won't be included if the URL is shared. - String sanitizedUrl = sanitizeUrl(currentUrl); + // Set the title as the tab text. + tabTitleTextView.setText(R.string.new_tab); + } + } else { // The WebView has loaded a webpage. + // Update the URL edit text if it is not currently being edited. + if (!urlEditText.hasFocus()) { + // Sanitize the current URL. This removes unwanted URL elements that were added by redirects, so that they won't be included if the URL is shared. + String sanitizedUrl = sanitizeUrl(currentUrl); - // Display the final URL. Getting the URL from the WebView instead of using the one provided by `onPageFinished()` makes websites like YouTube function correctly. - urlEditText.setText(sanitizedUrl); + // Display the final URL. Getting the URL from the WebView instead of using the one provided by `onPageFinished()` makes websites like YouTube function correctly. + urlEditText.setText(sanitizedUrl); - // Apply text highlighting to the URL. - highlightUrlText(); - } + // Apply text highlighting to the URL. + highlightUrlText(); + } - // Only populate the title text view if the tab has been fully created. - if (tab != null) { - // Get the custom view from the tab. - View tabView = tab.getCustomView(); + // Only populate the title text view if the tab has been fully created. + if (tab != null) { + // Get the custom view from the tab. + View tabView = tab.getCustomView(); - // Remove the incorrect warning below that the current tab view might be null. - assert tabView != null; + // Remove the incorrect warning below that the current tab view might be null. + assert tabView != null; - // Get the title text view from the tab. - TextView tabTitleTextView = tabView.findViewById(R.id.title_textview); + // Get the title text view from the tab. + TextView tabTitleTextView = tabView.findViewById(R.id.title_textview); - // Set the title as the tab text. Sometimes `onReceivedTitle()` is not called, especially when navigating history. - tabTitleTextView.setText(nestedScrollWebView.getTitle()); - } + // Set the title as the tab text. Sometimes `onReceivedTitle()` is not called, especially when navigating history. + tabTitleTextView.setText(nestedScrollWebView.getTitle()); } } } @@ -6203,42 +6292,43 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Apply the app settings from the shared preferences. applyAppSettings(); - // Load the website if not waiting for Orbot to connect. - if (!waitingForOrbot) { - // Get the intent that started the app. - Intent launchingIntent = getIntent(); + // Initialize the URL to load string. + String urlToLoadString; - // Get the information from the intent. - String launchingIntentAction = launchingIntent.getAction(); - Uri launchingIntentUriData = launchingIntent.getData(); + // Get the intent that started the app. + Intent launchingIntent = getIntent(); - // 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; + // Get the information from the intent. + String launchingIntentAction = launchingIntent.getAction(); + Uri launchingIntentUriData = launchingIntent.getData(); + + // Parse the launching intent URL. + if ((launchingIntentAction != null) && launchingIntentAction.equals(Intent.ACTION_WEB_SEARCH)) { // The intent contains a search string. + // Create an encoded URL string. + String encodedUrlString; + + // Sanitize the search input and convert it to a search. + try { + encodedUrlString = URLEncoder.encode(launchingIntent.getStringExtra(SearchManager.QUERY), "UTF-8"); + } catch (UnsupportedEncodingException exception) { + encodedUrlString = ""; + } - // Sanitize the search input and convert it to a search. - try { - encodedUrlString = URLEncoder.encode(launchingIntent.getStringExtra(SearchManager.QUERY), "UTF-8"); - } catch (UnsupportedEncodingException exception) { - encodedUrlString = ""; - } + // Store the web search as the URL to load. + urlToLoadString = searchURL + encodedUrlString; + } else if (launchingIntentUriData != null){ // The intent contains a URL. + // Store the URL. + urlToLoadString = launchingIntentUriData.toString(); + } else { // The is no URL in the intent. + // Store the homepage to be loaded. + urlToLoadString = sharedPreferences.getString("homepage", getString(R.string.homepage_default_value)); + } - // Load the completed search URL. - loadUrl(searchURL + encodedUrlString); - } else if (launchingIntentUriData != null){ // Check to see if the intent contains a new URL. - // Load the URL from the intent. - loadUrl(launchingIntentUriData.toString()); - } else { // The is no URL in the intent. - // Select the homepage based on the proxy through Orbot status. - if (proxyThroughOrbot) { - // Load the Tor homepage. - loadUrl(sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value))); - } else { - // Load the normal homepage. - loadUrl(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value))); - } - } + // Load the website if not waiting for the proxy. + if (waitingForProxy) { // Store the URL to be loaded in the Nested Scroll WebView. + nestedScrollWebView.setWaitingForProxyUrlString(urlToLoadString); + } else { // Load the URL. + loadUrl(nestedScrollWebView, urlToLoadString); } } else { // This is not the first tab. // Apply the domain settings.