/*
- * Copyright © 2015-2018 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2015-2019 Soren Stoutner <soren@stoutner.com>.
*
* Download cookie code contributed 2017 Hendrik Knackstedt. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
*
import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
// Update `findOnPageCountTextView`.
mainWebView.setFindListener(new WebView.FindListener() {
// Get a handle for `findOnPageCountTextView`.
- final TextView findOnPageCountTextView = (TextView) findViewById(R.id.find_on_page_count_textview);
+ final TextView findOnPageCountTextView = findViewById(R.id.find_on_page_count_textview);
@Override
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
int databaseID = (int) id;
// Get the bookmark cursor for this ID and move it to the first row.
- Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmarkCursor(databaseID);
+ Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseID);
bookmarkCursor.moveToFirst();
// Act upon the bookmark according to the type.
if (nightMode) {
// `background-color: #212121` sets the background to be dark gray. `color: #BDBDBD` sets the text color to be light gray. `box-shadow: none` removes a lower underline on links
// used by WordPress. `text-decoration: none` removes all text underlines. `text-shadow: none` removes text shadows, which usually have a hard coded color.
- // `border: none` removes all borders, which can also be used to underline text.
- // `a {color: #1565C0}` sets links to be a dark blue. `!important` takes precedent over any existing sub-settings.
+ // `border: none` removes all borders, which can also be used to underline text. `a {color: #1565C0}` sets links to be a dark blue.
+ // `::selection {background: #0D47A1}' sets the text selection highlight color to be a dark blue. `!important` takes precedent over any existing sub-settings.
mainWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; " +
"style.innerHTML = '* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important;" +
- "text-shadow: none !important; border: none !important;} a {color: #1565C0 !important;}'; parent.appendChild(style)})()", value -> {
+ "text-shadow: none !important; border: none !important;} a {color: #1565C0 !important;} ::selection {background: #0D47A1 !important;}'; parent.appendChild(style)})()", value -> {
// Initialize a handler to display `mainWebView`.
Handler displayWebViewHandler = new Handler();
// Setup a runnable to display `mainWebView` after a delay to allow the CSS to be applied.
Runnable displayWebViewRunnable = () -> {
- // Only display `mainWebView` if the progress bar is one. This prevents the display of the `WebView` while it is still loading.
+ // Only display `mainWebView` if the progress bar is gone. This prevents the display of the `WebView` while it is still loading.
if (progressBar.getVisibility() == View.GONE) {
mainWebView.setVisibility(View.VISIBLE);
}
// Hide zoom controls.
mainWebView.getSettings().setDisplayZoomControls(false);
- // Set `mainWebView` to use a wide viewport. Otherwise, some web pages will be scrunched and some content will render outside the screen.
+ // Don't allow mixed content (HTTP and HTTPS) on the same website.
+ if (Build.VERSION.SDK_INT >= 21) {
+ mainWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW);
+ }
+
+ // Set the WebView to use a wide viewport. Otherwise, some web pages will be scrunched and some content will render outside the screen.
mainWebView.getSettings().setUseWideViewPort(true);
- // Set `mainWebView` to load in overview mode (zoomed out to the maximum width).
+ // Set the WebView to load in overview mode (zoomed out to the maximum width).
mainWebView.getSettings().setLoadWithOverviewMode(true);
// Explicitly disable geolocation.
// Check to see if Privacy Browser is waiting on Orbot.
if (!waitingForOrbot) { // We are not waiting on Orbot, so we need to process the URL.
- // We need to update `formattedUrlString` at the beginning of the load, so that if the user toggles JavaScript during the load the new website is reloaded.
+ // The formatted URL string must be updated 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 formatted URL text.
// Apply the domain settings. This clears any settings from the previous domain.
applyDomainSettings(formattedUrlString, true, false);
} else { // `WebView` has loaded a webpage.
- // Set `formattedUrlString`.
- formattedUrlString = url;
+ // Set the formatted URL string. Getting the URL from the WebView instead of using the one provided by `onPageFinished` makes websites like YouTube function correctly.
+ formattedUrlString = mainWebView.getUrl();
- // Only update `urlTextBox` if the user is not typing in it.
+ // Only update the URL text box if the user is not typing in it.
if (!urlTextBox.hasFocus()) {
// Display the formatted URL text.
urlTextBox.setText(formattedUrlString);
printManager.print(getString(R.string.privacy_browser_web_page), printDocumentAdapter, null);
return true;
+ case R.id.find_on_page:
+ // Hide the URL app bar.
+ supportAppBar.setVisibility(View.GONE);
+
+ // Show the Find on Page `RelativeLayout`.
+ findOnPageLinearLayout.setVisibility(View.VISIBLE);
+
+ // Display the keyboard. We have to wait 200 ms before running the command to work around a bug in Android.
+ // http://stackoverflow.com/questions/5520085/android-show-softkeyboard-with-showsoftinput-is-not-working
+ findOnPageEditText.postDelayed(() -> {
+ // Set the focus on `findOnPageEditText`.
+ findOnPageEditText.requestFocus();
+
+ // Display the keyboard. `0` sets no input flags.
+ inputMethodManager.showSoftInput(findOnPageEditText, 0);
+ }, 200);
+ return true;
+
+ case R.id.add_to_homescreen:
+ // Show the alert dialog.
+ AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcutDialog();
+ createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getString(R.string.create_shortcut));
+
+ //Everything else will be handled by the alert dialog and the associated listener below.
+ return true;
+
case R.id.view_source:
// Launch the View Source activity.
Intent viewSourceIntent = new Intent(this, ViewSourceActivity.class);
startActivity(viewSourceIntent);
return true;
- case R.id.proxy_through_orbot:
- // Toggle the proxy through Orbot variable.
- proxyThroughOrbot = !proxyThroughOrbot;
-
- // Apply the proxy through Orbot settings.
- applyProxyThroughOrbot(true);
- return true;
-
- case R.id.share:
+ case R.id.share_url:
// Setup the share string.
String shareString = webViewTitle + " – " + urlTextBox.getText().toString();
shareIntent.setType("text/plain");
// Make it so.
- startActivity(Intent.createChooser(shareIntent, "Share URL"));
+ startActivity(Intent.createChooser(shareIntent, getString(R.string.share_url)));
return true;
- case R.id.find_on_page:
- // Hide the URL app bar.
- supportAppBar.setVisibility(View.GONE);
+ case R.id.open_with_app:
+ // Create the open with intent with `ACTION_VIEW`.
+ Intent openWithAppIntent = new Intent(Intent.ACTION_VIEW);
- // Show the Find on Page `RelativeLayout`.
- findOnPageLinearLayout.setVisibility(View.VISIBLE);
+ // Set the URI but not the MIME type. This should open all available apps.
+ openWithAppIntent.setData(Uri.parse(formattedUrlString));
- // Display the keyboard. We have to wait 200 ms before running the command to work around a bug in Android.
- // http://stackoverflow.com/questions/5520085/android-show-softkeyboard-with-showsoftinput-is-not-working
- findOnPageEditText.postDelayed(() -> {
- // Set the focus on `findOnPageEditText`.
- findOnPageEditText.requestFocus();
+ // Flag the intent to open in a new task.
+ openWithAppIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // Display the keyboard. `0` sets no input flags.
- inputMethodManager.showSoftInput(findOnPageEditText, 0);
- }, 200);
+ // Show the chooser.
+ startActivity(Intent.createChooser(openWithAppIntent, getString(R.string.open_with)));
return true;
- case R.id.add_to_homescreen:
- // Show the `CreateHomeScreenShortcutDialog` `AlertDialog` and name this instance `R.string.create_shortcut`.
- AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcutDialog();
- createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getString(R.string.create_shortcut));
+ case R.id.open_with_browser:
+ // Create the open with intent with `ACTION_VIEW`.
+ Intent openWithBrowserIntent = new Intent(Intent.ACTION_VIEW);
+
+ // Set the URI and the MIME type. `"text/html"` should load browser options.
+ openWithBrowserIntent.setDataAndType(Uri.parse(formattedUrlString), "text/html");
- //Everything else will be handled by `CreateHomeScreenShortcutDialog` and the associated listener below.
+ // Flag the intent to open in a new task.
+ openWithBrowserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Show the chooser.
+ startActivity(Intent.createChooser(openWithBrowserIntent, getString(R.string.open_with)));
+ return true;
+
+ case R.id.proxy_through_orbot:
+ // Toggle the proxy through Orbot variable.
+ proxyThroughOrbot = !proxyThroughOrbot;
+
+ // Apply the proxy through Orbot settings.
+ applyProxyThroughOrbot(true);
return true;
case R.id.refresh:
// Create the bookmark.
bookmarksDatabaseHelper.createBookmark(bookmarkNameString, bookmarkUrlString, currentBookmarksFolder, newBookmarkDisplayOrder, favoriteIconByteArray);
- // Update `bookmarksCursor` with the current contents of this folder.
- bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder);
+ // Update the bookmarks cursor with the current contents of this folder.
+ bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
// Update the `ListView`.
bookmarksCursorAdapter.changeCursor(bookmarksCursor);
// Create the folder, which will be placed at the top of the `ListView`.
bookmarksDatabaseHelper.createFolder(folderNameString, currentBookmarksFolder, folderIconByteArray);
- // Update `bookmarksCursor` with the current contents of this folder.
- bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder);
+ // Update the bookmarks cursor with the current contents of this folder.
+ bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
// Update the `ListView`.
bookmarksCursorAdapter.changeCursor(bookmarksCursor);
bookmarksDatabaseHelper.updateBookmark(selectedBookmarkDatabaseId, bookmarkNameString, bookmarkUrlString, newFavoriteIconByteArray);
}
- // Update `bookmarksCursor` with the current contents of this folder.
- bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder);
+ // Update the bookmarks cursor with the current contents of this folder.
+ bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
// Update the `ListView`.
bookmarksCursorAdapter.changeCursor(bookmarksCursor);
bookmarksDatabaseHelper.updateFolder(selectedFolderDatabaseId, oldFolderNameString, newFolderNameString, folderIconByteArray);
}
- // Update `bookmarksCursor` with the current contents of this folder.
- bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder);
+ // Update the bookmarks cursor with the current contents of this folder.
+ bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
// Update the `ListView`.
bookmarksCursorAdapter.changeCursor(bookmarksCursor);
drawerLayout.closeDrawer(GravityCompat.END);
} else { // A subfolder is displayed.
// Place the former parent folder in `currentFolder`.
- currentBookmarksFolder = bookmarksDatabaseHelper.getParentFolder(currentBookmarksFolder);
+ currentBookmarksFolder = bookmarksDatabaseHelper.getParentFolderName(currentBookmarksFolder);
// Load the new folder.
loadBookmarksFolder();
// Create a download intent. Not specifying the action type will display the maximum number of options.
Intent downloadIntent = new Intent();
- // Set the URI and the mime type. `"*/*"` will display the maximum number of options.
+ // Set the URI and the MIME type. Specifying `text/html` displays a good number of options.
downloadIntent.setDataAndType(Uri.parse(url), "text/html");
// Flag the intent to open in a new task.
private void loadBookmarksFolder() {
// Update the bookmarks cursor with the contents of the bookmarks database for the current folder.
- bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder);
+ bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
// Populate the bookmarks cursor adapter. `this` specifies the `Context`. `false` disables `autoRequery`.
bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) {