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=02f3742f179468bd309cea8788235046733b433a;hp=107a9cee6a83d538ff49b724f39f51f3da3b139a;hb=74857298f431569df1849e8ef91387cb25274095;hpb=0c865fd72ca80ba5c1452501ea667bbe30b41b2c 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 107a9cee..02f3742f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -34,6 +34,7 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -59,7 +60,10 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatDialogFragment; import android.support.v7.widget.Toolbar; import android.text.Editable; +import android.text.Spanned; import android.text.TextWatcher; +import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; import android.util.Patterns; import android.view.ContextMenu; import android.view.GestureDetector; @@ -118,8 +122,8 @@ import java.util.Set; public class MainWebViewActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, CreateHomeScreenShortcutDialog.CreateHomeScreenSchortcutListener, SslCertificateErrorDialog.SslCertificateErrorListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, UrlHistoryDialog.UrlHistoryListener { - // `appBar` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onOptionsItemSelected()`, `closeFindOnPage()`, and `applyAppSettings()`. - public static ActionBar appBar; + // `darkTheme` is public static so it can be accessed from `AboutActivity` and `GuideActivity`. It is also used in `onCreate()`, `applyAppSettings()`, and `applyDomainSettings()`. + public static boolean darkTheme; // `favoriteIconBitmap` is public static so it can be accessed from `CreateHomeScreenShortcutDialog`, `BookmarksActivity`, `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `ViewSslCertificateDialog`. // It is also used in `onCreate()`, `onCreateHomeScreenShortcutCreate()`, and `applyDomainSettings`. @@ -138,9 +142,15 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // `webViewTitle` is public static so it can be accessed from `CreateBookmarkDialog` and `CreateHomeScreenShortcutDialog`. It is also used in `onCreate()`. public static String webViewTitle; - // `displayWebpageImagesBoolean` is public static so it can be accessed from `DomainSettingsFragment`. It is also used in `applyAppSettings` and `applyDomainSettings()`. + // `displayWebpageImagesBoolean` is public static so it can be accessed from `DomainSettingsFragment`. It is also used in `applyAppSettings()` and `applyDomainSettings()`. public static boolean displayWebpageImagesBoolean; + // `reloadOnRestartBoolean` is public static so it can be accessed from `SettingsFragment`. It is also used in `onRestart()` + public static boolean reloadOnRestartBoolean; + + + // `appBar` is used in `onCreate()`, `onOptionsItemSelected()`, `closeFindOnPage()`, and `applyAppSettings()`. + private ActionBar appBar; // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, and `applyDomainSettings()`. private boolean navigatingHistory; @@ -237,9 +247,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // `onTheFlyDisplayImagesSet` is used in `applyDomainSettings()` and `setDisplayWebpageImages()`. private boolean onTheFlyDisplayImagesSet; - // `loadingNewIntentBoolean` is used in `onNewIntent()` and `onRestart()`. - private boolean loadingNewIntentBoolean; - // `waitingForOrbotData` is used in `onCreate()` and `applyAppSettings()`. private String waitingForOrbotHTMLString; @@ -261,9 +268,21 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // `supportAppBar` is used in `onCreate()`, `onOptionsItemSelected()`, and `closeFindOnPage()`. private Toolbar supportAppBar; - // `urlTextBox` is used in `onCreate()`, `onOptionsItemSelected()`, `loadUrlFromTextBox()`, and `loadUrl()`. + // `urlTextBox` is used in `onCreate()`, `onOptionsItemSelected()`, `loadUrlFromTextBox()`, `loadUrl()`, and `highlightUrlText()`. private EditText urlTextBox; + // `redColorSpan` is used in `onCreate()` and `highlightUrlText()`. + private ForegroundColorSpan redColorSpan; + + // `initialGrayColorSpan` is sued in `onCreate()` and `highlightUrlText()`. + private ForegroundColorSpan initialGrayColorSpan; + + // `finalGrayColorSpam` is used in `onCreate()` and `highlightUrlText()`. + private ForegroundColorSpan finalGrayColorSpan; + + // `boldStyleSpan` is used in `onCreate()` and `highlightUrlText()`. + private StyleSpan boldStyleSpan; + // `adView` is used in `onCreate()` and `onConfigurationChanged()`. private View adView; @@ -279,8 +298,26 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation @Override // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled. The whole premise of Privacy Browser is built around an understanding of these dangers. @SuppressLint("SetJavaScriptEnabled") + // Remove Android Studio's warning about deprecations. We have to use the deprecated `getColor()` until API >= 23. + @SuppressWarnings("deprecation") protected void onCreate(Bundle savedInstanceState) { + // Get a handle for `sharedPreferences`. `this` references the current context. + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + + // Get the theme preference. + darkTheme = sharedPreferences.getBoolean("dark_theme", false); + + // Set the activity theme. + if (darkTheme) { + setTheme(R.style.PrivacyBrowserDark); + } else { + setTheme(R.style.PrivacyBrowserLight); + } + + // Run the default commands. super.onCreate(savedInstanceState); + + // Set the content view. setContentView(R.layout.main_drawerlayout); // Get a handle for `inputMethodManager`. @@ -298,8 +335,36 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation appBar.setCustomView(R.layout.url_app_bar); appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); - // Set the "go" button on the keyboard to load the URL in urlTextBox. + // Initialize the `ForegroundColorSpans` and `StyleSpan` for highlighting `urlTextBox`. We have to use the deprecated `getColor()` until API >= 23. + redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700)); + initialGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500)); + finalGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500)); + boldStyleSpan = new StyleSpan(Typeface.BOLD); + + // Get a handle for `urlTextBox`. urlTextBox = (EditText) appBar.getCustomView().findViewById(R.id.url_edittext); + + // Remove the formatting from `urlTextBar` when the user is editing the text. + urlTextBox.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { // The user is editing `urlTextBox`. + // Remove the highlighting. + urlTextBox.getText().removeSpan(redColorSpan); + urlTextBox.getText().removeSpan(initialGrayColorSpan); + urlTextBox.getText().removeSpan(finalGrayColorSpan); + urlTextBox.getText().removeSpan(boldStyleSpan); + } else { // The user has stopped editing `urlTextBox`. + // Reapply the highlighting. + highlightUrlText(); + + // Scroll to the beginning of the text. + urlTextBox.setScrollX(0); + } + } + }); + + // Set the `Go` button on the keyboard to load the URL in `urlTextBox`. urlTextBox.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { @@ -547,8 +612,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation navigationForwardMenuItem.setEnabled(mainWebView.canGoForward()); navigationHistoryMenuItem.setEnabled((mainWebView.canGoBack() || mainWebView.canGoForward())); - // Hide the keyboard so we can see the navigation menu. `0` indicates no additional flags. + // Hide the keyboard (if displayed) so we can see the navigation menu. `0` indicates no additional flags. inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0); + + // Clear the focus from `urlTextBox` if it has it. + urlTextBox.clearFocus(); } } }); @@ -656,8 +724,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // We need to update `formattedUrlString` at the beginning of the load, so that if the user toggles JavaScript during the load the new website is reloaded. formattedUrlString = url; - // Display the loading URL is the URL text box. - urlTextBox.setText(url); + // Display the formatted URL text. + urlTextBox.setText(formattedUrlString); + + // Apply text highlighting to `urlTextBox`. + highlightUrlText(); // Apply any custom domain settings if the URL was loaded by navigating history. if (navigatingHistory) { @@ -696,7 +767,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Set `formattedUrlString` to `""`. formattedUrlString = ""; - // Update `urlTextBox`. urlTextBox.setText(formattedUrlString); // Request focus for `urlTextBox`. @@ -705,7 +775,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Display the keyboard. inputMethodManager.showSoftInput(urlTextBox, 0); - // Apply the domain settings. + // Apply the domain settings. This clears any settings from the previous domain. applyDomainSettings(formattedUrlString); } else { // `WebView` has loaded a webpage. // Set `formattedUrlString`. @@ -713,7 +783,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Only update `urlTextBox` if the user is not typing in it. if (!urlTextBox.hasFocus()) { + // Display the formatted URL text. urlTextBox.setText(formattedUrlString); + + // Apply text highlighting to `urlTextBox`. + highlightUrlText(); } } @@ -911,9 +985,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation @Override protected void onNewIntent(Intent intent) { - // Set `loadingNewIntentBoolean`. - loadingNewIntentBoolean = true; - // Sets the new intent as the activity intent, so that any future `getIntent()`s pick up this one instead of creating a new activity. setIntent(intent); @@ -948,13 +1019,13 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Set the display webpage images mode. setDisplayWebpageImages(); - // Only reload `mainWebView` if not loading a new intent. - if (!loadingNewIntentBoolean) { - // Reload the webpage to remove images if `setDisplayWebpageImages` has turned them off. + // Reload the webpage if displaying of images has been disabled in `SettingsFragment`. + if (reloadOnRestartBoolean) { + // Reload `mainWebView`. mainWebView.reload(); - } else { - // Reset `loadingNewIntentBoolean`. - loadingNewIntentBoolean = false; + + // Reset `reloadOnRestartBoolean`. + reloadOnRestartBoolean = false; } } @@ -1259,24 +1330,91 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation return true; case R.id.clear_cookies: - if (Build.VERSION.SDK_INT < 21) { - cookieManager.removeAllCookie(); - } else { - cookieManager.removeAllCookies(null); - } - Snackbar.make(findViewById(R.id.main_webview), R.string.cookies_deleted, Snackbar.LENGTH_SHORT).show(); + Snackbar.make(findViewById(R.id.main_webview), R.string.cookies_deleted, Snackbar.LENGTH_LONG) + .setAction(R.string.undo, new View.OnClickListener() { + @Override + public void onClick(View v) { + // Do nothing because everything will be handled by `onDismissed()` below. + } + }) + .addCallback(new Snackbar.Callback() { + @Override + public void onDismissed(Snackbar snackbar, int event) { + switch (event) { + // The user pushed the `Undo` button. + case Snackbar.Callback.DISMISS_EVENT_ACTION: + // Do nothing. + break; + + // The `Snackbar` was dismissed without the `Undo` button being pushed. + default: + // `cookieManager.removeAllCookie()` varies by SDK. + if (Build.VERSION.SDK_INT < 21) { + cookieManager.removeAllCookie(); + } else { + // `null` indicates no callback. + cookieManager.removeAllCookies(null); + } + } + } + }) + .show(); return true; case R.id.clear_dom_storage: - WebStorage webStorage = WebStorage.getInstance(); - webStorage.deleteAllData(); - Snackbar.make(findViewById(R.id.main_webview), R.string.dom_storage_deleted, Snackbar.LENGTH_SHORT).show(); + Snackbar.make(findViewById(R.id.main_webview), R.string.dom_storage_deleted, Snackbar.LENGTH_LONG) + .setAction(R.string.undo, new View.OnClickListener() { + @Override + public void onClick(View v) { + // Do nothing because everything will be handled by `onDismissed()` below. + } + }) + .addCallback(new Snackbar.Callback() { + @Override + public void onDismissed(Snackbar snackbar, int event) { + switch (event) { + // The user pushed the `Undo` button. + case Snackbar.Callback.DISMISS_EVENT_ACTION: + // Do nothing. + break; + + // The `Snackbar` was dismissed without the `Undo` button being pushed. + default: + // Delete the DOM Storage. + WebStorage webStorage = WebStorage.getInstance(); + webStorage.deleteAllData(); + } + } + }) + .show(); return true; case R.id.clear_form_data: - WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(this); - mainWebViewDatabase.clearFormData(); - Snackbar.make(findViewById(R.id.main_webview), R.string.form_data_deleted, Snackbar.LENGTH_SHORT).show(); + Snackbar.make(findViewById(R.id.main_webview), R.string.form_data_deleted, Snackbar.LENGTH_LONG) + .setAction(R.string.undo, new View.OnClickListener() { + @Override + public void onClick(View v) { + // Do nothing because everything will be handled by `onDismissed()` below. + } + }) + .addCallback(new Snackbar.Callback() { + @Override + public void onDismissed(Snackbar snackbar, int event) { + switch (event) { + // The user pushed the `Undo` button. + case Snackbar.Callback.DISMISS_EVENT_ACTION: + // Do nothing. + break; + + // The `Snackbar` was dismissed without the `Undo` button being pushed. + default: + // Delete the form data. + WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(getApplicationContext()); + mainWebViewDatabase.clearFormData(); + } + } + }) + .show(); return true; case R.id.font_size_twenty_five_percent: @@ -1481,30 +1619,83 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation break; case R.id.clearAndExit: - // Clear cookies. The commands changed slightly in API 21. - if (Build.VERSION.SDK_INT >= 21) { - cookieManager.removeAllCookies(null); - } else { - cookieManager.removeAllCookie(); + // Get a handle for `sharedPreferences`. `this` references the current context. + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + + boolean clearEverything = sharedPreferences.getBoolean("clear_everything", true); + + // Clear cookies. + if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) { + // The command to remove cookies changed slightly in API 21. + if (Build.VERSION.SDK_INT >= 21) { + cookieManager.removeAllCookies(null); + } else { + cookieManager.removeAllCookie(); + } + + // Manually delete the cookies database, as `CookieManager` sometimes will not flush its changes to disk before `System.exit(0)` is run. + try { + // We have to use two commands because `Runtime.exec()` does not like `*`. + privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies"); + privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies-journal"); + } catch (IOException e) { + // Do nothing if an error is thrown. + } } // Clear DOM storage. - WebStorage domStorage = WebStorage.getInstance(); - domStorage.deleteAllData(); + if (clearEverything || sharedPreferences.getBoolean("clear_dom_storage", true)) { + // Ask `WebStorage` to clear the DOM storage. + WebStorage webStorage = WebStorage.getInstance(); + webStorage.deleteAllData(); + + // Manually delete the DOM storage directory, as `WebStorage` sometimes will not flush its changes to disk before `System.exit(0)` is run. + try { + // We have to use a `String[]` because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise. + privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"}); + } catch (IOException e) { + // Do nothing if an error is thrown. + } + } // Clear form data. - WebViewDatabase webViewDatabase = WebViewDatabase.getInstance(this); - webViewDatabase.clearFormData(); + if (clearEverything || sharedPreferences.getBoolean("clear_form_data", true)) { + WebViewDatabase webViewDatabase = WebViewDatabase.getInstance(this); + webViewDatabase.clearFormData(); - // Clear the cache. `true` includes disk files. - mainWebView.clearCache(true); + // Manually delete the form data database, as `WebViewDatabase` sometimes will not flush its changes to disk before `System.exit(0)` is run. + try { + // We have to use a `String[]` because the database contains a space and `Runtime.exec` will not escape the string correctly otherwise. + privacyBrowserRuntime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data"}); + privacyBrowserRuntime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data-journal"}); + } catch (IOException e) { + // Do nothing if an error is thrown. + } + } - // Clear the back/forward history. - mainWebView.clearHistory(); + // Clear the cache. + if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) { + // `true` includes disk files. + mainWebView.clearCache(true); - // Clear any SSL certificate preferences. + // Manually delete the cache directories. + try { + // Delete the main cache directory. + privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache"); + + // Delete the secondary `Service Worker` cache directory. We have to use a `String[]` because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise. + privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"}); + } catch (IOException e) { + // Do nothing if an error is thrown. + } + } + + // Clear SSL certificate preferences. mainWebView.clearSslPreferences(); + // Clear the back/forward history. + mainWebView.clearHistory(); + // Clear `formattedUrlString`. formattedUrlString = null; @@ -1517,15 +1708,14 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Destroy the internal state of `mainWebView`. mainWebView.destroy(); - // Manually delete cache folders. - try { - // Delete the main `cache` folder. - privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache"); - - // Delete the `app_webview` folder, which contains an additional `WebView` cache. See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`. - privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview"); - } catch (IOException e) { - // Do nothing if an error is thrown. + // Manually delete the `app_webview` folder, which contains the cookies, DOM storage, form data, and `Service Worker` cache. + // See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`. + if (clearEverything) { + try { + privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview"); + } catch (IOException e) { + // Do nothing if an error is thrown. + } } // Close Privacy Browser. `finishAndRemoveTask` also removes Privacy Browser from the recent app list. @@ -1538,9 +1728,6 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Remove the terminated program from RAM. The status code is `0`. System.exit(0); break; - - default: - break; } // Close the navigation drawer. @@ -1786,6 +1973,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(imageUrl)); // Pass cookies to download manager if cookies are enabled. This is required to download images from websites that require a login. + // Code contributed 2017 Hendrik Knackstedt. Copyright assigned to Soren Stoutner . if (firstPartyCookiesEnabled) { // Get the cookies for `imageUrl`. String cookies = cookieManager.getCookie(imageUrl); @@ -1833,6 +2021,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(downloadUrl)); // Pass cookies to download manager if cookies are enabled. This is required to download files from websites that require a login. + // Code contributed 2017 Hendrik Knackstedt. Copyright assigned to Soren Stoutner . if (firstPartyCookiesEnabled) { // Get the cookies for `downloadUrl`. String cookies = cookieManager.getCookie(downloadUrl); @@ -2005,11 +2194,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation } private void applyAppSettings() { - // Get the shared preference values. `this` references the current context. + // Get a handle for `sharedPreferences`. `this` references the current context. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); // Store the values from `sharedPreferences` in variables. - String homepageString = sharedPreferences.getString("homepage", "https://duckduckgo.com"); + String homepageString = sharedPreferences.getString("homepage", "https://start.duckduckgo.com"); String torHomepageString = sharedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion"); String torSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q="); String torSearchCustomURLString = sharedPreferences.getString("tor_search_custom_url", ""); @@ -2045,6 +2234,13 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Set the proxy. `this` refers to the current activity where an `AlertDialog` might be displayed. OrbotProxyHelper.setProxy(getApplicationContext(), this, "localhost", "8118"); + // Set the `appBar` background to indicate proxying through Orbot is enabled. `this` refers to the context. + if (darkTheme) { + appBar.setBackgroundDrawable(ContextCompat.getDrawable(this, R.color.dark_blue_30)); + } else { + appBar.setBackgroundDrawable(ContextCompat.getDrawable(this, R.color.blue_50)); + } + // Display a message to the user if we are waiting on Orbot. if (!orbotStatus.equals("ON")) { // Set `waitingForOrbot`. @@ -2072,6 +2268,13 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation // Reset the proxy to default. The host is `""` and the port is `"0"`. OrbotProxyHelper.setProxy(getApplicationContext(), this, "", "0"); + // Set the default `appBar` background. `this` refers to the context. + if (darkTheme) { + appBar.setBackgroundDrawable(ContextCompat.getDrawable(this, R.color.gray_900)); + } else { + appBar.setBackgroundDrawable(ContextCompat.getDrawable(this, R.color.gray_100)); + } + // Reset `waitingForOrbot. waitingForOrbot = false; } @@ -2271,7 +2474,11 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation } // 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. - urlAppBarRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_green)); + if (darkTheme) { + urlAppBarRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + } else { + urlAppBarRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + } } else { // The URL we are loading does not have custom domain settings. Load the defaults. // Store the values from `sharedPreferences` in variables. javaScriptEnabled = sharedPreferences.getBoolean("javascript_enabled", false); @@ -2314,7 +2521,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation } // Set a transparent background on `urlTextBox`. We have to use the deprecated `.getDrawable()` until the minimum API >= 21. - urlAppBarRelativeLayout.setBackgroundDrawable(getResources().getDrawable(R.drawable.url_bar_background_transparent)); + urlAppBarRelativeLayout.setBackgroundDrawable(getResources().getDrawable(R.color.transparent)); } // Close `domainsDatabaseHelper`. @@ -2397,4 +2604,23 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation ActivityCompat.invalidateOptionsMenu(this); } } + + private void highlightUrlText() { + String urlString = urlTextBox.getText().toString(); + + if (urlString.startsWith("http://")) { // Highlight connections that are not encrypted. + urlTextBox.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + urlTextBox.getText().setSpan(boldStyleSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } else if (urlString.startsWith("https://")) { // Highlight connections that are encrypted. + urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + + // Get the index of the `/` immediately after the domain name. + int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2)); + + // De-emphasize the text after the domain name. + if (endOfDomainName > 0) { + urlTextBox.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + } }