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=caecde4c46dca4427dda9e01a137eded16325e21;hp=1ec5a020037e08504db735b8d43fc6ecd1c00184;hb=af807cce079aaae9cbf0430e7da946fcbe0c99c3;hpb=16ccee9956383ad3a38b09f7a4f7e9aeee92cd42 diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index 1ec5a020..caecde4c 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -46,7 +46,6 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.net.http.SslCertificate; import android.net.http.SslError; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; @@ -103,29 +102,31 @@ import androidx.core.content.ContextCompat; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.viewpager.widget.ViewPager; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.navigation.NavigationView; import com.google.android.material.snackbar.Snackbar; - import com.google.android.material.tabs.TabLayout; + import com.stoutner.privacybrowser.BuildConfig; import com.stoutner.privacybrowser.R; +import com.stoutner.privacybrowser.adapters.WebViewPagerAdapter; +import com.stoutner.privacybrowser.asynctasks.GetHostIpAddresses; import com.stoutner.privacybrowser.dialogs.AdConsentDialog; import com.stoutner.privacybrowser.dialogs.CreateBookmarkDialog; import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog; import com.stoutner.privacybrowser.dialogs.CreateHomeScreenShortcutDialog; +import com.stoutner.privacybrowser.dialogs.DownloadFileDialog; 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.HttpAuthenticationDialog; import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog; +import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog; import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog; import com.stoutner.privacybrowser.dialogs.ViewSslCertificateDialog; import com.stoutner.privacybrowser.fragments.WebViewTabFragment; @@ -134,8 +135,6 @@ import com.stoutner.privacybrowser.helpers.BlockListHelper; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper; import com.stoutner.privacybrowser.helpers.OrbotProxyHelper; -import com.stoutner.privacybrowser.dialogs.DownloadFileDialog; -import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog; import com.stoutner.privacybrowser.views.NestedScrollWebView; import java.io.ByteArrayInputStream; @@ -143,18 +142,14 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.lang.ref.WeakReference; -import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -165,22 +160,26 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook EditBookmarkFolderDialog.EditBookmarkFolderListener, HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener, WebViewTabFragment.NewTabListener, PinnedMismatchDialog.PinnedMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener { + // TODO Consider removing // `darkTheme` is public static so it can be accessed from everywhere. public static boolean darkTheme; + // TODO Consider removing // `allowScreenshots` is public static so it can be accessed from everywhere. It is also used in `onCreate()`. public static boolean allowScreenshots; - // `favoriteIconBitmap` is public static so it can be accessed from `CreateHomeScreenShortcutDialog`, `BookmarksActivity`, `BookmarksDatabaseViewActivity`, `CreateBookmarkDialog`, - // `CreateBookmarkFolderDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `EditBookmarkDatabaseViewDialog`, and `ViewSslCertificateDialog`. It is also used in `onCreate()`, - // `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onCreateHomeScreenShortcut()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `applyDomainSettings()`. + // TODO Remove + // `favoriteIconBitmap` is public static so it can be accessed from `BookmarksActivity`, `BookmarksDatabaseViewActivity`, `CreateBookmarkFolderDialog`, + // `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `EditBookmarkDatabaseViewDialog`, and `ViewSslCertificateDialog`. It is also used in `onCreate()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, + // `onCreateHomeScreenShortcut()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `applyDomainSettings()`. public static Bitmap favoriteIconBitmap; + // TODO Remove // `favoriteIconDefaultBitmap` public static so it can be accessed from `PinnedMismatchDialog`. It is also used in `onCreate()` and `applyDomainSettings`. public static Bitmap favoriteIconDefaultBitmap; - // `formattedUrlString` is public static so it can be accessed from `AddDomainDialog`, `BookmarksActivity`, `DomainSettingsFragment`, `CreateBookmarkDialog`, - // and `PinnedMismatchDialog`. + // TODO Consider removing the formatted URL string. + // `formattedUrlString` is public static so it can be accessed from `AddDomainDialog`, `BookmarksActivity`, `DomainSettingsFragment`, and `PinnedMismatchDialog`. // It is also used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onCreateHomeScreenShortcutCreate()`, `loadUrlFromTextBox()`, and `applyProxyThroughOrbot()`. public static String formattedUrlString; @@ -188,16 +187,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // It is also used in `onCreate()` and `checkPinnedMismatch()`. public static SslCertificate sslCertificate; - // `currentHostIpAddresses` is public static so it can be accessed from `DomainSettingsFragment` and `ViewSslCertificateDialog`. + // `currentHostIpAddresses` is public static so it can be accessed from `DomainSettingsFragment`, `GetHostIpAddresses()`, and `ViewSslCertificateDialog`. // It is also used in `onCreate()` and `GetHostIpAddresses()`. public static String currentHostIpAddresses; + // The getting IP addresses tracker is used in `onCreate() and `GetHostIpAddresses`. + public static boolean gettingIpAddresses; + + // The URL loading tracker is public static so it can be accessed from `GetHostIpAddresses`. + // It is also used in `onCreate()`, `onCreateOptionsMenu()`, `loadUrl()`, `applyDomainSettings()`, and `GetHostIpAddresses`. + public static boolean urlIsLoading; + // `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. public static String orbotStatus; - // `webViewTitle` is public static so it can be accessed from `CreateBookmarkDialog`. It is also used in `onCreate()`. - public static String webViewTitle; - // `appliedUserAgentString` is public static so it can be accessed from `ViewSourceActivity`. It is also used in `applyDomainSettings()`. public static String appliedUserAgentString; @@ -272,9 +275,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`. public static String currentBookmarksFolder; - // `domainSettingsDatabaseId` is public static so it can be accessed from `PinnedMismatchDialog`. It is also used in `onCreate()`, `onOptionsItemSelected()`, and `applyDomainSettings()`. - public static int domainSettingsDatabaseId; - // The pinned variables are public static so they can be accessed from `PinnedMismatchDialog`. They are also used in `onCreate()`, `applyDomainSettings()`, and `checkPinnedMismatch()`. public static String pinnedSslIssuedToCName; public static String pinnedSslIssuedToOName; @@ -296,12 +296,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook - // `urlIsLoading` is used in `onCreate()`, `onCreateOptionsMenu()`, `loadUrl()`, `applyDomainSettings()`, and `GetHostIpAddresses`. - private static boolean urlIsLoading; - - // `gettingIpAddresses` is used in `onCreate() and `GetHostIpAddresses`. - private static boolean gettingIpAddresses; - // `pinnedDomainSslCertificate` is used in `onCreate()`, `applyDomainSettings()`, and `checkPinnedMismatch()`. private static boolean pinnedSslCertificate; @@ -322,7 +316,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private boolean navigatingHistory; // The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, - // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, and `applyProxyThroughOrbot()`. + // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxyThroughOrbot()`, and `applyDomainSettings()`. private NestedScrollWebView currentWebView; // `fullScreenVideoFrameLayout` is used in `onCreate()` and `onConfigurationChanged()`. @@ -441,9 +435,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `waitingForOrbot` is used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`. private boolean waitingForOrbot; - // `domainSettingsApplied` is used in `prepareOptionsMenu()` and `applyDomainSettings()`. - private boolean domainSettingsApplied; - // `domainSettingsJavaScriptEnabled` is used in `onOptionsItemSelected()` and `applyDomainSettings()`. private Boolean domainSettingsJavaScriptEnabled; @@ -462,9 +453,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`. private ActionBarDrawerToggle actionBarDrawerToggle; - // `urlTextBox` is used in `onCreate()`, `onOptionsItemSelected()`, `loadUrlFromTextBox()`, `loadUrl()`, and `highlightUrlText()`. - private EditText urlTextBox; - // The color spans are used in `onCreate()` and `highlightUrlText()`. private ForegroundColorSpan redColorSpan; private ForegroundColorSpan initialGrayColorSpan; @@ -568,7 +556,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // This is needed to get rid of the Android Studio warning that the action bar might be null. assert actionBar != null; - // Add the custom `url_app_bar` layout, which shows the favorite icon and the URL text bar. + // Add the custom layout, which shows the URL text bar. actionBar.setCustomView(R.layout.url_app_bar); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); @@ -578,18 +566,18 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook finalGrayColorSpan = new ForegroundColorSpan(resources.getColor(R.color.gray_500)); // Get a handle for `urlTextBox`. - urlTextBox = findViewById(R.id.url_edittext); + EditText urlEditText = findViewById(R.id.url_edittext); // Remove the formatting from `urlTextBar` when the user is editing the text. - urlTextBox.setOnFocusChangeListener((View v, boolean hasFocus) -> { + urlEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> { if (hasFocus) { // The user is editing the URL text box. // Remove the highlighting. - urlTextBox.getText().removeSpan(redColorSpan); - urlTextBox.getText().removeSpan(initialGrayColorSpan); - urlTextBox.getText().removeSpan(finalGrayColorSpan); + urlEditText.getText().removeSpan(redColorSpan); + urlEditText.getText().removeSpan(initialGrayColorSpan); + urlEditText.getText().removeSpan(finalGrayColorSpan); } else { // The user has stopped editing the URL text box. // Move to the beginning of the string. - urlTextBox.setSelection(0); + urlEditText.setSelection(0); // Reapply the highlighting. highlightUrlText(); @@ -597,7 +585,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook }); // Set the go button on the keyboard to load the URL in `urlTextBox`. - urlTextBox.setOnKeyListener((View v, int keyCode, KeyEvent event) -> { + urlEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> { // If the event is a key-down event on the `enter` button, load the URL. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { // Load the URL into the mainWebView and consume the event. @@ -703,15 +691,44 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override public void onPageSelected(int position) { - // TODO. Consider using an array of the WebViews. - // Get the current WebView fragment. Instantiate item returns the current item if it already exists. - Fragment webViewFragment = (Fragment) webViewPagerAdapter.instantiateItem(webViewPager, position); + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(position); + + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); - // Remove the lint error below that the WebView fragment might be null. - assert webViewFragment.getView() != null; + // Remove the incorrect lint warning below that the fragment view might be null. + assert fragmentView != null; // Store the current WebView. - currentWebView = webViewFragment.getView().findViewById(R.id.nestedscroll_webview); + currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Store the current formatted URL string. + formattedUrlString = currentWebView.getUrl(); + + // Clear the focus from the URL text box. + urlEditText.clearFocus(); + + // Hide the soft keyboard. + inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); + + // Display the current URL in the URL text box. + urlEditText.setText(formattedUrlString); + + // Highlight the URL text. + highlightUrlText(); + + // Set the background to indicate the domain settings status. + if (currentWebView.getDomainSettingsApplied()) { + // Set a green background on `urlTextBox` to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + if (darkTheme) { + urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + } else { + urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + } + } else { + urlEditText.setBackgroundDrawable(getResources().getDrawable(R.color.transparent)); + } // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled via swiping in the view pager. if (tabLayout.getSelectedTabPosition() != position) { @@ -755,8 +772,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); - // Add the first tab. - webViewPagerAdapter.addPage(); + // Add the first tab. (It doesn't matter what view is passed. That is just required as part of the ImageView `onClick()` syntax). + addTab(webViewPager); // Set the bookmarks drawer resources according to the theme. This can't be done in the layout due to compatibility issues with the `DrawerLayout` support widget. if (darkTheme) { @@ -773,6 +790,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the launch bookmarks activity FAB to launch the bookmarks activity. launchBookmarksActivityFab.setOnClickListener(v -> { + // Store the current WebView url and title in the bookmarks activity. + BookmarksActivity.currentWebViewUrl = currentWebView.getUrl(); + BookmarksActivity.currentWebViewTitle = currentWebView.getTitle(); + // Create an intent to launch the bookmarks activity. Intent bookmarksIntent = new Intent(getApplicationContext(), BookmarksActivity.class); @@ -792,8 +813,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the create new bookmark FAB to display an alert dialog. createBookmarkFab.setOnClickListener(view -> { - // Show the create bookmark dialog and name the instance `@string/create_bookmark`. - DialogFragment createBookmarkDialog = new CreateBookmarkDialog(); + // Instantiate the create bookmark dialog. + DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebView.getUrl(), currentWebView.getTitle(), favoriteIconBitmap); + + // Display the create bookmark dialog. createBookmarkDialog.show(fragmentManager, resources.getString(R.string.create_bookmark)); }); @@ -819,7 +842,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the `check mark` button for the `findOnPageEditText` keyboard to close the soft keyboard. findOnPageEditText.setOnKeyListener((v, keyCode, event) -> { if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { // The `enter` key was pressed. - // Hide the soft keyboard. `0` indicates no additional flags. + // Hide the soft keyboard. inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); // Consume the event. @@ -962,7 +985,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); // Clear the focus from from the URL text box and the WebView. This removes any text selection markers and context menus, which otherwise draw above the open drawers. - urlTextBox.clearFocus(); + urlEditText.clearFocus(); currentWebView.clearFocus(); } } @@ -998,11 +1021,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook saveFormDataEnabled = false; // Form data can be removed once the minimum API >= 26. nightMode = false; + // Inflate a bare WebView to get the default user agent. It is not used to render content on the screen. + @SuppressLint("InflateParams") View webViewLayout = getLayoutInflater().inflate(R.layout.bare_webview, null, false); + + // Get a handle for the WebView. + WebView bareWebView = webViewLayout.findViewById(R.id.bare_webview); + // Store the default user agent. - // TODO webViewDefaultUserAgent = mainWebView.getSettings().getUserAgentString(); + webViewDefaultUserAgent = bareWebView.getSettings().getUserAgentString(); - // Initialize the WebView title. - webViewTitle = getString(R.string.no_title); + // Destroy the bare WebView. + bareWebView.destroy(); // Initialize the favorite icon bitmap. `ContextCompat` must be used until API >= 21. Drawable favoriteIconDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.world); @@ -1119,8 +1148,23 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Reload the webpage if displaying of images has been disabled in the Settings activity. if (reloadOnRestart) { // Reload the WebViews. - // TODO - currentWebView.reload(); + 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); + + // TODO this doesn't seem to work if for WebViews that aren't visible. + // Reload the WebView. + nestedScrollWebView.reload(); + } + } // Reset `reloadOnRestartBoolean`. reloadOnRestart = false; @@ -1173,11 +1217,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Run the default commands. super.onResume(); - // Resume JavaScript (if enabled). - // TODO mainWebView.resumeTimers(); + for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); - // Resume `mainWebView`. - // TODO mainWebView.onResume(); + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Only resume the WebViews if they exist (they won't when the app is first created). + if (fragmentView != null) { + // Get the nested scroll WebView from the tab fragment. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Resume the nested scroll WebView JavaScript timers. + nestedScrollWebView.resumeTimers(); + + // Resume the nested scroll WebView. + nestedScrollWebView.onResume(); + } + } // Display a message to the user if waiting for Orbot. if (waitingForOrbot && !orbotStatus.equals("ON")) { @@ -1214,13 +1272,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Run the default commands. super.onPause(); - // Pause `mainWebView`. - // TODO - currentWebView.onPause(); + for (int i = 0; i < webViewPagerAdapter.getCount(); i++) { + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i); - // Stop all JavaScript. - // TODO - currentWebView.pauseTimers(); + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Only pause the WebViews if they exist (they won't when the app is first created). + if (fragmentView != null) { + // Get the nested scroll WebView from the tab fragment. + NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Pause the nested scroll WebView. + nestedScrollWebView.onPause(); + + // Pause the nested scroll WebView JavaScript timers. + nestedScrollWebView.pauseTimers(); + } + } // Pause the ad or it will continue to consume resources in the background on the free flavor. if (BuildConfig.FLAVOR.contentEquals("free")) { @@ -1335,11 +1405,27 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem nightModeMenuItem = menu.findItem(R.id.night_mode); MenuItem proxyThroughOrbotMenuItem = menu.findItem(R.id.proxy_through_orbot); - // Set the text for the domain menu item. - if (domainSettingsApplied) { - addOrEditDomain.setTitle(R.string.edit_domain_settings); - } else { - addOrEditDomain.setTitle(R.string.add_domain_settings); + // Initialize the current user agent string and the font size. + String currentUserAgent = getString(R.string.user_agent_privacy_browser); + int fontSize = 100; + + // Set items that require the current web view to be populated. It will be null when the program is first opened, as `onPrepareOptionsMenu()` is called before the first WebView is initialized. + if (currentWebView != null) { + // Set the add or edit domain text. + if (currentWebView.getDomainSettingsApplied()) { + addOrEditDomain.setTitle(R.string.edit_domain_settings); + } else { + addOrEditDomain.setTitle(R.string.add_domain_settings); + } + + // Get the current user agent from the WebView. + currentUserAgent = currentWebView.getSettings().getUserAgentString(); + + // Get the current font size from the + fontSize = currentWebView.getSettings().getTextZoom(); + + // Set the status of the display images menu item. + displayImagesMenuItem.setChecked(currentWebView.getSettings().getLoadsImagesAutomatically()); } // Set the status of the menu item checkboxes. @@ -1354,7 +1440,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook ultraPrivacyMenuItem.setChecked(ultraPrivacyEnabled); blockAllThirdPartyRequestsMenuItem.setChecked(blockAllThirdPartyRequests); swipeToRefreshMenuItem.setChecked(swipeRefreshLayout.isEnabled()); - // TODO displayImagesMenuItem.setChecked(mainWebView.getSettings().getLoadsImagesAutomatically()); nightModeMenuItem.setChecked(nightMode); proxyThroughOrbotMenuItem.setChecked(proxyThroughOrbot); @@ -1408,10 +1493,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook ultraPrivacyMenuItem.setTitle(ultraPrivacyBlockedRequests + " - " + getString(R.string.ultraprivacy)); blockAllThirdPartyRequestsMenuItem.setTitle(thirdPartyBlockedRequests + " - " + getString(R.string.block_all_third_party_requests)); - // Get the current user agent. - // TODO String currentUserAgent = mainWebView.getSettings().getUserAgentString(); - String currentUserAgent = ""; - // 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. menu.findItem(R.id.user_agent_privacy_browser).setChecked(true); @@ -1441,9 +1522,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook menu.findItem(R.id.user_agent_custom).setChecked(true); } - // Initialize font size variables. - // TODO int fontSize = mainWebView.getSettings().getTextZoom(); - int fontSize = 100; + // Instantiate the font size title and the selected font size menu item. String fontSizeTitle; MenuItem selectedFontSizeMenuItem; @@ -1558,7 +1637,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return true; case R.id.add_or_edit_domain: - if (domainSettingsApplied) { // Edit the current domain settings. + if (currentWebView.getDomainSettingsApplied()) { // Edit the current domain settings. // Reapply the domain settings on returning to `MainWebViewActivity`. reapplyDomainSettingsOnRestart = true; currentDomainName = ""; @@ -1567,7 +1646,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook Intent domainsIntent = new Intent(this, DomainsActivity.class); // Put extra information instructing the domains activity to directly load the current domain and close on back instead of returning to the domains list. - domainsIntent.putExtra("loadDomain", domainSettingsDatabaseId); + domainsIntent.putExtra("loadDomain", currentWebView.getDomainSettingsDatabaseId()); domainsIntent.putExtra("closeOnBack", true); // Make it so. @@ -2043,7 +2122,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook if (nightMode) { // Night mode is enabled. Enable JavaScript. // Update the global variable. javaScriptEnabled = true; - } else if (domainSettingsApplied) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings. + } else if (currentWebView.getDomainSettingsApplied()) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings. // Get the JavaScript preference that was stored the last time domain settings were loaded. javaScriptEnabled = domainSettingsJavaScriptEnabled; } else { // Night mode is disabled and domain settings are not applied. Set JavaScript according to the global preference. @@ -2094,7 +2173,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.share_url: // Setup the share string. - String shareString = webViewTitle + " – " + urlTextBox.getText().toString(); + String shareString = currentWebView.getTitle() + " – " + formattedUrlString; // Create the share intent. Intent shareIntent = new Intent(Intent.ACTION_SEND); @@ -2181,7 +2260,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the current tab number. int currentTabNumber = tabLayout.getSelectedTabPosition(); - // Delete the tab and page. + // Delete the current tab. + tabLayout.removeTabAt(currentTabNumber); + + // Delete the current page. webViewPagerAdapter.deletePage(currentTabNumber); break; @@ -3270,8 +3352,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } private void loadUrlFromTextBox() { + // Get a handle for the URL edit text. + EditText urlEditText = findViewById(R.id.url_edittext); + // Get the text from urlTextBox and convert it to a string. trim() removes white spaces from the beginning and end of the string. - String unformattedUrlString = urlTextBox.getText().toString().trim(); + String unformattedUrlString = urlEditText.getText().toString().trim(); // Check to see if `unformattedUrlString` is a valid URL. Otherwise, convert it into a search. if (unformattedUrlString.startsWith("content://")) { @@ -3330,8 +3415,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = searchURL + encodedUrlString; } - // Clear the focus from the URL text box. Otherwise, proximate typing in the box will retain the colorized formatting instead of being reset during refocus. - urlTextBox.clearFocus(); + // Clear the focus from the URL edit text. Otherwise, proximate typing in the box will retain the colorized formatting instead of being reset during refocus. + urlEditText.clearFocus(); // Make it so. loadUrl(formattedUrlString); @@ -3411,8 +3496,24 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook customHeaders.remove("DNT"); } - // Set the app bar scrolling. - currentWebView.setNestedScrollingEnabled(sharedPreferences.getBoolean("scroll_app_bar", true)); + // TODO this also needs to be set when creating a new tab. + // Set the app bar scrolling for each WebView. + 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 modify 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); + + // Set the app bar scrolling. + nestedScrollWebView.setNestedScrollingEnabled(sharedPreferences.getBoolean("scroll_app_bar", true)); + } + } // Update the full screen browsing mode settings. if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) { // Privacy Browser is currently in full screen browsing mode. @@ -3559,21 +3660,26 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Close `domainNameCursor. domainNameCursor.close(); - // Initialize variables to track if domain settings will be applied and, if so, under which name. - domainSettingsApplied = false; + // Initialize the domain name in database variable. String domainNameInDatabase = null; - // Check the hostname. - if (domainSettingsSet.contains(hostName)) { - domainSettingsApplied = true; + // Check the hostname against the domain settings set. + if (domainSettingsSet.contains(hostName)) { // The hostname is contained in the domain settings set. + // Record the domain name in the database. domainNameInDatabase = hostName; + + // Set the domain settings applied tracker to true. + currentWebView.setDomainSettingsApplied(true); + } else { // The hostname is not contained in the domain settings set. + // Set the domain settings applied tracker to false. + currentWebView.setDomainSettingsApplied(false); } // Check all the subdomains of the host name against wildcard domains in the domain cursor. - while (!domainSettingsApplied && hostName.contains(".")) { // Stop checking if domain settings are already applied or there are no more `.` in the host name. + while (!currentWebView.getDomainSettingsApplied() && hostName.contains(".")) { // Stop checking if domain settings are already applied or there are no more `.` in the host name. if (domainSettingsSet.contains("*." + hostName)) { // Check the host name prepended by `*.`. - // Apply the domain settings. - domainSettingsApplied = true; + // Set the domain settings applied tracker to true. + currentWebView.setDomainSettingsApplied(true); // Store the applied domain names as it appears in the database. domainNameInDatabase = "*." + hostName; @@ -3595,13 +3701,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nightMode = sharedPreferences.getBoolean("night_mode", false); boolean displayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true); - if (domainSettingsApplied) { // The url has custom domain settings. + if (currentWebView.getDomainSettingsApplied()) { // The url has custom domain settings. // Get a cursor for the current host and move it to the first position. Cursor currentHostDomainSettingsCursor = domainsDatabaseHelper.getCursorForDomainName(domainNameInDatabase); currentHostDomainSettingsCursor.moveToFirst(); // Get the settings from the cursor. - domainSettingsDatabaseId = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); + currentWebView.setDomainSettingsDatabaseId(currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); javaScriptEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); firstPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1); thirdPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1); @@ -3775,7 +3881,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook break; } - // Set a green background on `urlTextBox` to indicate that custom domain settings are being used. We have to use the deprecated `.getDrawable()` until the minimum API >= 21. + // Set a green background on URL edit text to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. if (darkTheme) { urlEditText.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); } else { @@ -3813,7 +3919,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Reset the pinned variables. - domainSettingsDatabaseId = -1; + currentWebView.setDomainSettingsDatabaseId(-1); pinnedSslCertificate = false; pinnedSslIssuedToCName = ""; pinnedSslIssuedToOName = ""; @@ -3869,7 +3975,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the loading of webpage images. currentWebView.getSettings().setLoadsImagesAutomatically(displayWebpageImages); - // Set a transparent background on `urlTextBox`. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + // Set a transparent background on URL edit text. The deprecated `.getDrawable()` must be used until the minimum API >= 21. urlEditText.setBackgroundDrawable(getResources().getDrawable(R.color.transparent)); } @@ -3979,9 +4085,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Reset `waitingForOrbot. waitingForOrbot = false; - // Reload the website if requested. + // Reload the WebViews if requested. if (reloadWebsite) { - currentWebView.reload(); + // 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(); + } + } } } } @@ -4058,18 +4180,21 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } private void highlightUrlText() { + // Get a handle for the URL edit text. + EditText urlEditText = findViewById(R.id.url_edittext); + // Only highlight the URL text if the box is not currently selected. - if (!urlTextBox.hasFocus()) { + if (!urlEditText.hasFocus()) { // Get the URL string. - String urlString = urlTextBox.getText().toString(); + String urlString = urlEditText.getText().toString(); // Highlight the URL according to the protocol. if (urlString.startsWith("file://")) { // This is a file URL. // De-emphasize only the protocol. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } else if (urlString.startsWith("content://")) { // De-emphasize only the protocol. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } else { // This is a web URL. // Get the index of the `/` immediately after the domain name. int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2)); @@ -4094,25 +4219,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Markup the beginning of the URL. if (urlString.startsWith("http://")) { // Highlight the protocol of connections that are not encrypted. - urlTextBox.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); // De-emphasize subdomains. if (penultimateDotIndex > 0) { // There is more than one subdomain in the domain name. - urlTextBox.getText().setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } else if (urlString.startsWith("https://")) { // De-emphasize the protocol of connections that are encrypted. if (penultimateDotIndex > 0) { // There is more than one subdomain in the domain name. // De-emphasize the protocol and the additional subdomains. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } else { // There is only one subdomain in the domain name. // De-emphasize only the protocol. - urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } // De-emphasize the text after the domain name. if (endOfDomainName > 0) { - urlTextBox.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlEditText.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } } @@ -4197,7 +4322,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook startActivity(openWithBrowserIntent); } - private static void checkPinnedMismatch() { + public static void checkPinnedMismatch(int domainSettingsDatabaseId) { if ((pinnedSslCertificate || pinnedIpAddresses) && !ignorePinnedDomainInformation) { // Initialize the current SSL certificate variables. String currentWebsiteIssuedToCName = ""; @@ -4253,7 +4378,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook !currentWebsiteSslEndDateString.equals(pinnedSslEndDateString)))) { // Get a handle for the pinned mismatch alert dialog. - DialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(pinnedSslCertificate, pinnedIpAddresses); + DialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(domainSettingsDatabaseId, pinnedSslCertificate, pinnedIpAddresses); // Show the pinned mismatch alert dialog. pinnedMismatchDialogFragment.show(fragmentManager, "Pinned Mismatch"); @@ -4261,235 +4386,48 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `String` contains the results. - private static class GetHostIpAddresses extends AsyncTask { - // The weak references are used to determine if the activity have disappeared while the AsyncTask is running. - private final WeakReference activityWeakReference; - - GetHostIpAddresses(Activity activity) { - // Populate the weak references. - activityWeakReference = new WeakReference<>(activity); - } - - // `onPreExecute()` operates on the UI thread. - @Override - protected void onPreExecute() { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - return; - } - - // Set the getting IP addresses tracker. - gettingIpAddresses = true; - } - - - @Override - protected String doInBackground(String... domainName) { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - // Return an empty spannable string builder. - return ""; - } - - // Initialize an IP address string builder. - StringBuilder ipAddresses = new StringBuilder(); - - // Get an array with the IP addresses for the host. - try { - // Get an array with all the IP addresses for the domain. - InetAddress[] inetAddressesArray = InetAddress.getAllByName(domainName[0]); - - // Add each IP address to the string builder. - for (InetAddress inetAddress : inetAddressesArray) { - if (ipAddresses.length() == 0) { // This is the first IP address. - // Add the IP address to the string builder. - ipAddresses.append(inetAddress.getHostAddress()); - } else { // This is not the first IP address. - // Add a line break to the string builder first. - ipAddresses.append("\n"); - - // Add the IP address to the string builder. - ipAddresses.append(inetAddress.getHostAddress()); - } - } - } catch (UnknownHostException exception) { - // Do nothing. - } - - // Return the string. - return ipAddresses.toString(); - } - - // `onPostExecute()` operates on the UI thread. - @Override - protected void onPostExecute(String ipAddresses) { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - return; - } - - // Store the IP addresses. - currentHostIpAddresses = ipAddresses; - - if (!urlIsLoading) { - checkPinnedMismatch(); - } - - // Reset the getting IP addresses tracker. - gettingIpAddresses = false; - } - } - - private class WebViewPagerAdapter extends FragmentPagerAdapter { - // The WebView fragments list contains all the WebViews. - private LinkedList webViewFragmentsList = new LinkedList<>(); - - // Define the constructor. - private WebViewPagerAdapter(FragmentManager fragmentManager){ - // Run the default commands. - super(fragmentManager); - } - - @Override - public int getCount() { - // Return the number of pages. - return webViewFragmentsList.size(); - } - - @Override - public int getItemPosition(@NonNull Object object) { - //noinspection SuspiciousMethodCalls - if (webViewFragmentsList.contains(object)) { - // The tab has not been deleted. - return POSITION_UNCHANGED; - } else { - // The tab has been deleted. - return POSITION_NONE; - } - } - - @Override - public Fragment getItem(int pageNumber) { - // Get a WebView for a particular page. Page numbers are 0 indexed. - return webViewFragmentsList.get(pageNumber); - } - - private void addPage() { - // Add a new page. The pages and tabs are 0 indexed, so the size of the current list equals the number of the next page. - webViewFragmentsList.add(WebViewTabFragment.createTab(webViewFragmentsList.size())); - - // Update the view pager. - notifyDataSetChanged(); - } - - private void deletePage(int pageNumber) { - // Get a handle for the tab layout. - TabLayout tabLayout = findViewById(R.id.tablayout); - - // TODO always move to the next tab if possible. - // Select a tab that is not being deleted. - if (pageNumber == 0) { // The first tab is being deleted. - // Get a handle for the second tab. The tabs are 0 indexed. - TabLayout.Tab secondTab = tabLayout.getTabAt(1); - - // Remove the incorrect lint warning below that the second tab might be null. - assert secondTab != null; - - // Select the second tab. - secondTab.select(); - } else { // The first tab is not being deleted. - // Get a handle for the previous tab. - TabLayout.Tab previousTab = tabLayout.getTabAt(pageNumber - 1); + public void addTab(View view) { + // Get a handle for the tab layout. + TabLayout tabLayout = findViewById(R.id.tablayout); - // Remove the incorrect lint warning below tha the previous tab might be null. - assert previousTab != null; + // Get the new page number. The page numbers are 0 indexed, so the new page number will match the current count. + int newTabNumber = tabLayout.getTabCount(); - // Select the previous tab. - previousTab.select(); - } + // Add a new tab. + tabLayout.addTab(tabLayout.newTab()); - // Delete the page. - webViewFragmentsList.remove(pageNumber); + // Get the new tab. + TabLayout.Tab newTab = tabLayout.getTabAt(newTabNumber); - // Delete the tab. - tabLayout.removeTabAt(pageNumber); + // Remove the lint warning below that the current tab might be null. + assert newTab != null; - // Update the view pager. - notifyDataSetChanged(); - } - } + // Set a custom view on the current tab. + newTab.setCustomView(R.layout.custom_tab_view); - public void addTab(View view) { // Add the new WebView page. - webViewPagerAdapter.addPage(); - - // Get a handle for the tab layout. - TabLayout tabLayout = findViewById(R.id.tablayout); - - // Get a handle for the new tab. The tabs are 0 indexed. - TabLayout.Tab newTab = tabLayout.getTabAt(tabLayout.getTabCount() - 1); - - // Remove the incorrect warning below that the new tab might be null. - assert newTab != null; + webViewPagerAdapter.addPage(newTabNumber); - // Move the tab layout to the new tab. - newTab.select(); + if (newTabNumber > 0) { + // Move to the new tab. + newTab.select(); + } } @Override - public void initializeWebView(int tabNumber, ProgressBar progressBar, NestedScrollWebView nestedScrollWebView) { + public void initializeWebView(long pageId, int pageNumber, ProgressBar progressBar, NestedScrollWebView nestedScrollWebView) { // Get handles for the activity views. - final FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout); - final DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); - final RelativeLayout mainContentRelativeLayout = findViewById(R.id.main_content_relativelayout); - final ActionBar actionBar = getSupportActionBar(); - final TabLayout tabLayout = findViewById(R.id.tablayout); - final SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swiperefreshlayout); + FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout); + DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); + RelativeLayout mainContentRelativeLayout = findViewById(R.id.main_content_relativelayout); + ActionBar actionBar = getSupportActionBar(); + EditText urlEditText = findViewById(R.id.url_edittext); + TabLayout tabLayout = findViewById(R.id.tablayout); + SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swiperefreshlayout); // Remove the incorrect lint warnings below that the some of the views might be null. assert actionBar != null; - // TODO. Still doesn't work right. - // Create the tab if it doesn't already exist. - try { - TabLayout.Tab tab = tabLayout.getTabAt(tabNumber); - - assert tab != null; - - tab.getCustomView(); - } catch (Exception exception) { - tabLayout.addTab(tabLayout.newTab()); - } - - // Get the current tab. - TabLayout.Tab currentTab = tabLayout.getTabAt(tabNumber); - - // Remove the lint warning below that the current tab might be null. - assert currentTab != null; - - // Set a custom view on the current tab. - currentTab.setCustomView(R.layout.custom_tab_view); - - // Get the custom view from the tab. - View currentTabView = currentTab.getCustomView(); - - // Remove the incorrect warning below that the current tab view might be null. - assert currentTabView != null; - - // Get the current views from the tab. - ImageView tabFavoriteIconImageView = currentTabView.findViewById(R.id.favorite_icon_imageview); - TextView tabTitleTextView = currentTabView.findViewById(R.id.title_textview); - // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); @@ -4713,9 +4651,27 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Only update the favorite icon if the website has finished loading. if (progressBar.getVisibility() == View.GONE) { // Save a copy of the favorite icon. - // TODO. We need to save and access the icons for each tab. favoriteIconBitmap = icon; + // Get the current page position. + int currentPosition = webViewPagerAdapter.getPositionForId(pageId); + + // Get the current tab. + TabLayout.Tab tab = tabLayout.getTabAt(currentPosition); + + // Remove the lint warning below that the current tab might be null. + assert 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; + + // Get the favorite icon image view from the tab. + ImageView tabFavoriteIconImageView = tabView.findViewById(R.id.favorite_icon_imageview); + + // Display the favorite icon in the tab. tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true)); } } @@ -4723,12 +4679,26 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Save a copy of the title when it changes. @Override public void onReceivedTitle(WebView view, String title) { - // Save a copy of the title. - // TODO. Replace `webViewTitle` with `currentWebView.getTitle()`. - webViewTitle = title; + // Get the current page position. + int currentPosition = webViewPagerAdapter.getPositionForId(pageId); + + // Get the current tab. + TabLayout.Tab tab = tabLayout.getTabAt(currentPosition); + + // Remove the lint warning below that the current tab might be null. + assert 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; + + // 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(webViewTitle); + tabTitleTextView.setText(title); } // Enter full screen video. @@ -5166,7 +5136,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = url; // Display the formatted URL text. - urlTextBox.setText(formattedUrlString); + urlEditText.setText(formattedUrlString); // Apply text highlighting to `urlTextBox`. highlightUrlText(); @@ -5175,7 +5145,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook Uri currentUri = Uri.parse(formattedUrlString); // Get the IP addresses for the host. - new GetHostIpAddresses(activity).execute(currentUri.getHost()); + new GetHostIpAddresses(activity, currentWebView.getDomainSettingsDatabaseId()).execute(currentUri.getHost()); // Apply any custom domain settings if the URL was loaded by navigating history. if (navigatingHistory) { @@ -5266,13 +5236,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set `formattedUrlString` to `""`. formattedUrlString = ""; - urlTextBox.setText(formattedUrlString); + urlEditText.setText(formattedUrlString); // Request focus for `urlTextBox`. - urlTextBox.requestFocus(); + urlEditText.requestFocus(); // Display the keyboard. - inputMethodManager.showSoftInput(urlTextBox, 0); + inputMethodManager.showSoftInput(urlEditText, 0); // Apply the domain settings. This clears any settings from the previous domain. applyDomainSettings(formattedUrlString, true, false); @@ -5281,9 +5251,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook formattedUrlString = nestedScrollWebView.getUrl(); // Only update the URL text box if the user is not typing in it. - if (!urlTextBox.hasFocus()) { + if (!urlEditText.hasFocus()) { // Display the formatted URL text. - urlTextBox.setText(formattedUrlString); + urlEditText.setText(formattedUrlString); // Apply text highlighting to `urlTextBox`. highlightUrlText(); @@ -5295,7 +5265,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Check the current website information against any pinned domain information if the current IP addresses have been loaded. if (!gettingIpAddresses) { - checkPinnedMismatch(); + checkPinnedMismatch(currentWebView.getDomainSettingsDatabaseId()); } } @@ -5339,8 +5309,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); - // Check to see if this is the first tab. - if (tabNumber == 0) { + // Check to see if this is the first page. + if (pageNumber == 0) { // Set this nested scroll WebView as the current WebView. currentWebView = nestedScrollWebView;