+ // Remove the formatting from the URL edit text when the user is editing the text.
+ urlEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> {
+ if (hasFocus) { // The user is editing the URL text box.
+ // Remove the syntax highlighting.
+ 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.
+ urlEditText.setSelection(0);
+
+ // Reapply the syntax highlighting.
+ UrlHelper.highlightSyntax(urlEditText, initialGrayColorSpan, finalGrayColorSpan, redColorSpan);
+ }
+ });
+
+ // Set the go button on the keyboard to load the URL in `urlTextBox`.
+ 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.
+ loadUrlFromTextBox();
+
+ // If the enter key was pressed, consume the event.
+ return true;
+ } else {
+ // If any other key was pressed, do not consume the event.
+ return false;
+ }
+ });
+
+ // 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 the proxy, load the website now that Orbot is connected.
+ if ((orbotStatus != null) && orbotStatus.equals(ProxyHelper.ORBOT_STATUS_ON) && waitingForProxy) {
+ // Reset the waiting for proxy status.
+ waitingForProxy = false;
+
+ // Get a list of the current fragments.
+ List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
+
+ // Check each fragment to see if it is a waiting for proxy dialog. Sometimes more than one is displayed.
+ for (int i = 0; i < fragmentList.size(); i++) {
+ // Get the fragment tag.
+ String fragmentTag = fragmentList.get(i).getTag();
+
+ // Check to see if it is the waiting for proxy dialog.
+ if ((fragmentTag!= null) && fragmentTag.equals(getString(R.string.waiting_for_proxy_dialog))) {
+ // Dismiss the waiting for proxy dialog.
+ ((DialogFragment) fragmentList.get(i)).dismiss();
+ }
+ }
+
+ // Reload existing URLs and 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);
+
+ // Get the fragment view.
+ View fragmentView = webViewTabFragment.getView();
+
+ // 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()) { // A URL is waiting to be loaded.
+ // Load the URL.
+ loadUrl(nestedScrollWebView, waitingForProxyUrlString);
+
+ // Reset the waiting for proxy URL string.
+ nestedScrollWebView.setWaitingForProxyUrlString("");
+ } else { // No URL is waiting to be loaded.
+ // Reload the existing URL.
+ nestedScrollWebView.reload();
+ }
+ }
+ }
+ }
+ }
+ };
+
+ // 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.
+ LinearLayout bookmarksHeaderLinearLayout = findViewById(R.id.bookmarks_header_linearlayout);
+ ListView bookmarksListView = findViewById(R.id.bookmarks_drawer_listview);
+ FloatingActionButton launchBookmarksActivityFab = findViewById(R.id.launch_bookmarks_activity_fab);
+ FloatingActionButton createBookmarkFolderFab = findViewById(R.id.create_bookmark_folder_fab);
+ FloatingActionButton createBookmarkFab = findViewById(R.id.create_bookmark_fab);
+ EditText findOnPageEditText = findViewById(R.id.find_on_page_edittext);
+
+ // Update the web view pager every time a tab is modified.
+ webViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ // Close the find on page bar if it is open.
+ closeFindOnPage(null);
+
+ // Set the current WebView.
+ setCurrentWebView(position);
+
+ // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled by creating a new tab.
+ if (tabLayout.getSelectedTabPosition() != position) {
+ // Wait until the new tab has been created.
+ tabLayout.post(() -> {
+ // Get a handle for the tab.
+ TabLayout.Tab tab = tabLayout.getTabAt(position);
+
+ // Assert that the tab is not null.
+ assert tab != null;
+
+ // Select the tab.
+ tab.select();
+ });
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ // Do nothing.
+ }
+ });
+
+ // Display the View SSL Certificate dialog when the currently selected tab is reselected.
+ tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
+ @Override
+ public void onTabSelected(TabLayout.Tab tab) {
+ // Select the same page in the view pager.
+ webViewPager.setCurrentItem(tab.getPosition());
+ }
+
+ @Override
+ public void onTabUnselected(TabLayout.Tab tab) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onTabReselected(TabLayout.Tab tab) {
+ // Instantiate the View SSL Certificate dialog.
+ DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId(), currentWebView.getFavoriteIcon());
+
+ // Display the View SSL Certificate dialog.
+ viewSslCertificateDialogFragment.show(getSupportFragmentManager(), getString(R.string.view_ssl_certificate));
+ }
+ });
+
+ // Set a touch listener on the bookmarks header linear layout so that touches don't pass through to the button underneath.
+ bookmarksHeaderLinearLayout.setOnTouchListener((view, motionEvent) -> {
+ // Consume the touch.
+ return true;
+ });
+
+ // Set the launch bookmarks activity FAB to launch the bookmarks activity.
+ launchBookmarksActivityFab.setOnClickListener(v -> {
+ // Get a copy of the favorite icon bitmap.
+ Bitmap favoriteIconBitmap = currentWebView.getFavoriteIcon();
+
+ // Create a favorite icon byte array output stream.
+ ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream();
+
+ // Convert the favorite icon bitmap to a byte array. `0` is for lossless compression (the only option for a PNG).
+ favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream);
+
+ // Convert the favorite icon byte array stream to a byte array.
+ byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray();
+
+ // Create an intent to launch the bookmarks activity.
+ Intent bookmarksIntent = new Intent(getApplicationContext(), BookmarksActivity.class);