import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
+import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import com.stoutner.privacybrowser.dialogs.DownloadLocationPermissionDialog;
import com.stoutner.privacybrowser.dialogs.EditBookmarkDialog;
import com.stoutner.privacybrowser.dialogs.EditBookmarkFolderDialog;
+import com.stoutner.privacybrowser.dialogs.FontSizeDialog;
import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog;
+import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog;
import com.stoutner.privacybrowser.dialogs.SaveWebpageImageDialog;
import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog;
import com.stoutner.privacybrowser.dialogs.StoragePermissionDialog;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
// AppCompatActivity from android.support.v7.app.AppCompatActivity must be used to have access to the SupportActionBar until the minimum API is >= 21.
public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener,
DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener,
- EditBookmarkFolderDialog.EditBookmarkFolderListener, NavigationView.OnNavigationItemSelectedListener, PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageImageDialog.SaveWebpageImageListener,
- StoragePermissionDialog.StoragePermissionDialogListener, WebViewTabFragment.NewTabListener {
+ EditBookmarkFolderDialog.EditBookmarkFolderListener, FontSizeDialog.UpdateFontSizeListener, NavigationView.OnNavigationItemSelectedListener, PinnedMismatchDialog.PinnedMismatchListener, PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageImageDialog.SaveWebpageImageListener,
+ StoragePermissionDialog.StoragePermissionDialogListener, UrlHistoryDialog.NavigateHistoryListener, WebViewTabFragment.NewTabListener {
// `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`.
public static String orbotStatus;
@Override
protected void onNewIntent(Intent intent) {
+ // Run the default commands.
+ super.onNewIntent(intent);
+
// Replace the intent that started the app with this one.
setIntent(intent);
loadingNewIntent = true;
// Add a new tab.
- addNewTab(url);
+ addNewTab(url, true);
} else { // Load the URL in the current tab.
// Make it so.
loadUrl(url);
File localStorageDirectory = new File (privateDataDirectoryString + "/app_webview/Local Storage/");
int localStorageDirectoryNumberOfFiles = 0;
if (localStorageDirectory.exists()) {
- localStorageDirectoryNumberOfFiles = localStorageDirectory.list().length;
+ // `Objects.requireNonNull` removes a lint warning that `localStorageDirectory.list` might produce a null pointed exception if it is dereferenced.
+ localStorageDirectoryNumberOfFiles = Objects.requireNonNull(localStorageDirectory.list()).length;
}
// Get a count of the number of files in the IndexedDB directory.
File indexedDBDirectory = new File (privateDataDirectoryString + "/app_webview/IndexedDB");
int indexedDBDirectoryNumberOfFiles = 0;
if (indexedDBDirectory.exists()) {
- indexedDBDirectoryNumberOfFiles = indexedDBDirectory.list().length;
+ // `Objects.requireNonNull` removes a lint warning that `indexedDBDirectory.list` might produce a null pointed exception if it is dereferenced.
+ indexedDBDirectoryNumberOfFiles = Objects.requireNonNull(indexedDBDirectory.list()).length;
}
// Enable Clear DOM Storage if there is any.
menu.findItem(R.id.user_agent_custom).setChecked(true);
}
- // Instantiate the font size title and the selected font size menu item.
- String fontSizeTitle;
- MenuItem selectedFontSizeMenuItem;
-
- // Prepare the font size title and current size menu item.
- switch (fontSize) {
- case 25:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.twenty_five_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_twenty_five_percent);
- break;
-
- case 50:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.fifty_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_fifty_percent);
- break;
-
- case 75:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.seventy_five_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_seventy_five_percent);
- break;
-
- case 100:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_percent);
- break;
-
- case 125:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_twenty_five_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_twenty_five_percent);
- break;
-
- case 150:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_fifty_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_fifty_percent);
- break;
-
- case 175:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_seventy_five_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_seventy_five_percent);
- break;
-
- case 200:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.two_hundred_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_two_hundred_percent);
- break;
-
- default:
- fontSizeTitle = getString(R.string.font_size) + " - " + getString(R.string.one_hundred_percent);
- selectedFontSizeMenuItem = menu.findItem(R.id.font_size_one_hundred_percent);
- break;
- }
-
- // Set the font size title and select the current size menu item.
- fontSizeMenuItem.setTitle(fontSizeTitle);
- selectedFontSizeMenuItem.setChecked(true);
+ // Set the font size title.
+ fontSizeMenuItem.setTitle(getString(R.string.font_size) + " - " + fontSize + "%");
// Run all the other default commands.
super.onPrepareOptionsMenu(menu);
// Consume the event.
return true;
- case R.id.font_size_twenty_five_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(25);
-
- // Consume the event.
- return true;
+ case R.id.font_size:
+ // Instantiate the font size dialog.
+ DialogFragment fontSizeDialogFragment = FontSizeDialog.displayDialog(currentWebView.getSettings().getTextZoom());
- case R.id.font_size_fifty_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(50);
-
- // Consume the event.
- return true;
-
- case R.id.font_size_seventy_five_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(75);
-
- // Consume the event.
- return true;
-
- case R.id.font_size_one_hundred_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(100);
-
- // Consume the event.
- return true;
-
- case R.id.font_size_one_hundred_twenty_five_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(125);
-
- // Consume the event.
- return true;
-
- case R.id.font_size_one_hundred_fifty_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(150);
-
- // Consume the event.
- return true;
-
- case R.id.font_size_one_hundred_seventy_five_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(175);
-
- // Consume the event.
- return true;
-
- case R.id.font_size_two_hundred_percent:
- // Set the font size.
- currentWebView.getSettings().setTextZoom(200);
+ // Show the font size dialog.
+ fontSizeDialogFragment.show(getSupportFragmentManager(), getString(R.string.font_size));
// Consume the event.
return true;
case R.id.back:
if (currentWebView.canGoBack()) {
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the previous entry URL.
+ String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl();
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, previousUrl, false, false);
// Load the previous website in the history.
currentWebView.goBack();
case R.id.forward:
if (currentWebView.canGoForward()) {
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the next entry URL.
+ String nextUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() + 1).getUrl();
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, nextUrl, false, false);
// Load the next website in the history.
currentWebView.goForward();
}
@Override
- public void onConfigurationChanged(Configuration newConfig) {
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
// Run the default commands.
super.onConfigurationChanged(newConfig);
// Add an Open in New Tab entry.
menu.add(R.string.open_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> {
- // Load the link URL in a new tab.
- addNewTab(linkUrl);
+ // Load the link URL in a new tab and move to it.
+ addNewTab(linkUrl, true);
+
+ // Consume the event.
+ return true;
+ });
+
+ // Add an Open in Background entry.
+ menu.add(R.string.open_in_background).setOnMenuItemClickListener((MenuItem item) -> {
+ // Load the link URL in a new tab but do not move to it.
+ addNewTab(linkUrl, false);
// Consume the event.
return true;
menu.setHeaderTitle(imageUrl);
// Add an Open in New Tab entry.
- menu.add(R.string.open_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> {
- // Load the image URL in a new tab.
- addNewTab(imageUrl);
+ menu.add(R.string.open_image_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> {
+ // Load the image in a new tab.
+ addNewTab(imageUrl, true);
// Consume the event.
return true;
// Add an Open in New Tab entry.
menu.add(R.string.open_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> {
- // Load the link URL in a new tab.
- addNewTab(linkUrl);
+ // Load the link URL in a new tab and move to it.
+ addNewTab(linkUrl, true);
+
+ // Consume the event.
+ return true;
+ });
+
+ // Add an Open in Background entry.
+ menu.add(R.string.open_in_background).setOnMenuItemClickListener((MenuItem item) -> {
+ // Lod the link URL in a new tab but do not move to it.
+ addNewTab(linkUrl, false);
+
+ // Consume the event.
+ return true;
+ });
+
+ // Add an Open Image in New Tab entry.
+ menu.add(R.string.open_image_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> {
+ // Load the image in a new tab and move to it.
+ addNewTab(imageUrl, true);
// Consume the event.
return true;
// Get a handle for the bookmarks list view.
ListView bookmarksListView = findViewById(R.id.bookmarks_drawer_listview);
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get the views from the dialog fragment.
- EditText createBookmarkNameEditText = dialogFragment.getDialog().findViewById(R.id.create_bookmark_name_edittext);
- EditText createBookmarkUrlEditText = dialogFragment.getDialog().findViewById(R.id.create_bookmark_url_edittext);
+ EditText createBookmarkNameEditText = dialog.findViewById(R.id.create_bookmark_name_edittext);
+ EditText createBookmarkUrlEditText = dialog.findViewById(R.id.create_bookmark_url_edittext);
// Extract the strings from the edit texts.
String bookmarkNameString = createBookmarkNameEditText.getText().toString();
// Get a handle for the bookmarks list view.
ListView bookmarksListView = findViewById(R.id.bookmarks_drawer_listview);
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get handles for the views in the dialog fragment.
- EditText createFolderNameEditText = dialogFragment.getDialog().findViewById(R.id.create_folder_name_edittext);
- RadioButton defaultFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.create_folder_default_icon_radiobutton);
- ImageView folderIconImageView = dialogFragment.getDialog().findViewById(R.id.create_folder_default_icon);
+ EditText createFolderNameEditText = dialog.findViewById(R.id.create_folder_name_edittext);
+ RadioButton defaultFolderIconRadioButton = dialog.findViewById(R.id.create_folder_default_icon_radiobutton);
+ ImageView folderIconImageView = dialog.findViewById(R.id.create_folder_default_icon);
// Get new folder name string.
String folderNameString = createFolderNameEditText.getText().toString();
@Override
public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap) {
- // Get handles for the views from `dialogFragment`.
- EditText editBookmarkNameEditText = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_name_edittext);
- EditText editBookmarkUrlEditText = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_url_edittext);
- RadioButton currentBookmarkIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_current_icon_radiobutton);
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
+ // Get handles for the views from the dialog.
+ EditText editBookmarkNameEditText = dialog.findViewById(R.id.edit_bookmark_name_edittext);
+ EditText editBookmarkUrlEditText = dialog.findViewById(R.id.edit_bookmark_url_edittext);
+ RadioButton currentBookmarkIconRadioButton = dialog.findViewById(R.id.edit_bookmark_current_icon_radiobutton);
// Store the bookmark strings.
String bookmarkNameString = editBookmarkNameEditText.getText().toString();
@Override
public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap) {
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get handles for the views from `dialogFragment`.
- EditText editFolderNameEditText = dialogFragment.getDialog().findViewById(R.id.edit_folder_name_edittext);
- RadioButton currentFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_folder_current_icon_radiobutton);
- RadioButton defaultFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_folder_default_icon_radiobutton);
- ImageView defaultFolderIconImageView = dialogFragment.getDialog().findViewById(R.id.edit_folder_default_icon_imageview);
+ EditText editFolderNameEditText = dialog.findViewById(R.id.edit_folder_name_edittext);
+ RadioButton currentFolderIconRadioButton = dialog.findViewById(R.id.edit_folder_current_icon_radiobutton);
+ RadioButton defaultFolderIconRadioButton = dialog.findViewById(R.id.edit_folder_default_icon_radiobutton);
+ ImageView defaultFolderIconImageView = dialog.findViewById(R.id.edit_folder_default_icon_imageview);
// Get the new folder name.
String newFolderNameString = editFolderNameEditText.getText().toString();
downloadRequest.addRequestHeader("Cookie", cookies);
}
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get the file name from the dialog fragment.
- EditText downloadImageNameEditText = dialogFragment.getDialog().findViewById(R.id.download_image_name);
+ EditText downloadImageNameEditText = dialog.findViewById(R.id.download_image_name);
String imageName = downloadImageNameEditText.getText().toString();
// Specify the download location.
downloadRequest.addRequestHeader("Cookie", cookies);
}
- // Get the file name from the dialog fragment.
- EditText downloadFileNameEditText = dialogFragment.getDialog().findViewById(R.id.download_file_name);
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
+ // Get the file name from the dialog.
+ EditText downloadFileNameEditText = dialog.findViewById(R.id.download_file_name);
String fileName = downloadFileNameEditText.getText().toString();
// Specify the download location.
}
}
- // Override `onBackPressed` to handle the navigation drawer and and the WebView.
+ // Override `onBackPressed` to handle the navigation drawer and and the WebViews.
@Override
public void onBackPressed() {
// Get a handle for the drawer layout and the tab layout.
// Load the new folder.
loadBookmarksFolder();
}
+ } else if (displayingFullScreenVideo) { // A full screen video is shown.
+ // Get a handle for the layouts.
+ FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout);
+ RelativeLayout mainContentRelativeLayout = findViewById(R.id.main_content_relativelayout);
+ FrameLayout fullScreenVideoFrameLayout = findViewById(R.id.full_screen_video_framelayout);
+
+ // Re-enable the screen timeout.
+ fullScreenVideoFrameLayout.setKeepScreenOn(false);
+
+ // Unset the full screen video flag.
+ displayingFullScreenVideo = false;
+
+ // Remove all the views from the full screen video frame layout.
+ fullScreenVideoFrameLayout.removeAllViews();
+
+ // Hide the full screen video frame layout.
+ fullScreenVideoFrameLayout.setVisibility(View.GONE);
+
+ // Enable the sliding drawers.
+ drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
+
+ // Show the main content relative layout.
+ mainContentRelativeLayout.setVisibility(View.VISIBLE);
+
+ // Apply the appropriate full screen mode flags.
+ if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) { // Privacy Browser is currently in full screen browsing mode.
+ // Hide the app bar if specified.
+ if (hideAppBar) {
+ // Get handles for the views.
+ LinearLayout tabsLinearLayout = findViewById(R.id.tabs_linearlayout);
+ ActionBar actionBar = getSupportActionBar();
+
+ // Remove the incorrect lint warning below that the action bar might be null.
+ assert actionBar != null;
+
+ // Hide the tab linear layout.
+ tabsLinearLayout.setVisibility(View.GONE);
+
+ // Hide the action bar.
+ actionBar.hide();
+ }
+
+ // Hide the banner ad in the free flavor.
+ if (BuildConfig.FLAVOR.contentEquals("free")) {
+ AdHelper.hideAd(findViewById(R.id.adview));
+ }
+
+ // Remove the translucent status flag. This is necessary so the root frame layout can fill the entire screen.
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+ /* Hide the system bars.
+ * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
+ * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar.
+ * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
+ * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
+ */
+ rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ } else { // Switch to normal viewing mode.
+ // Remove the `SYSTEM_UI` flags from the root frame layout.
+ rootFrameLayout.setSystemUiVisibility(0);
+
+ // Add the translucent status flag.
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ }
+
+ // Reload the ad for the free flavor if not in full screen mode.
+ if (BuildConfig.FLAVOR.contentEquals("free") && !inFullScreenBrowsingMode) {
+ // Reload the ad.
+ AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_unit_id));
+ }
} else if (currentWebView.canGoBack()) { // There is at least one item in the current WebView history.
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the previous entry URL.
+ String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl();
- // Set navigating history so that the domain settings are applied when the new URL is loaded.
- currentWebView.setNavigatingHistory(true);
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, previousUrl, false, false);
// Go back.
currentWebView.goBack();
// Close the current tab.
closeCurrentTab();
} else { // There isn't anything to do in Privacy Browser.
- // Run the default commands.
- super.onBackPressed();
+ // Close Privacy Browser. `finishAndRemoveTask()` also removes Privacy Browser from the recent app list.
+ if (Build.VERSION.SDK_INT >= 21) {
+ finishAndRemoveTask();
+ } else {
+ finish();
+ }
// Manually kill Privacy Browser. Otherwise, it is glitchy when restarted.
System.exit(0);
// Process the results of a file browse.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // Run the default commands.
+ super.onActivityResult(requestCode, resultCode, data);
+
// Run the commands that correlate to the specified request code.
switch (requestCode) {
case FILE_UPLOAD_REQUEST_CODE:
// Get a handle for the save webpage image dialog.
Dialog saveWebpageImageDialog = saveWebpageImageDialogFragment.getDialog();
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert saveWebpageImageDialog != null;
+
// Get a handle for the file name edit text.
EditText fileNameEditText = saveWebpageImageDialog.findViewById(R.id.file_name_edittext);
// Instantiate the file name helper.
FileNameHelper fileNameHelper = new FileNameHelper();
- // Convert the file name URI to a file name path.
- String fileNamePath = fileNameHelper.convertUriToFileNamePath(data.getData());
+ // Get the file path if it isn't null.
+ if (data.getData() != null) {
+ // Convert the file name URI to a file name path.
+ String fileNamePath = fileNameHelper.convertUriToFileNamePath(data.getData());
- // Set the file name path as the text of the file name edit text.
- fileNameEditText.setText(fileNamePath);
+ // Set the file name path as the text of the file name edit text.
+ fileNameEditText.setText(fileNamePath);
+ }
}
}
break;
inputMethodManager.hideSoftInputFromWindow(toolbar.getWindowToken(), 0);
}
+ @Override
+ public void onApplyNewFontSize(DialogFragment dialogFragment) {
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below tha the dialog might be null.
+ assert dialog != null;
+
+ // Get a handle for the font size edit text.
+ EditText fontSizeEditText = dialog.findViewById(R.id.font_size_edittext);
+
+ // Initialize the new font size variable with the current font size.
+ int newFontSize = currentWebView.getSettings().getTextZoom();
+
+ // Get the font size from the edit text.
+ try {
+ newFontSize = Integer.valueOf(fontSizeEditText.getText().toString());
+ } catch (Exception exception) {
+ // If the edit text does not contain a valid font size do nothing.
+ }
+
+ // Apply the new font size.
+ currentWebView.getSettings().setTextZoom(newFontSize);
+ }
+
@Override
public void onSaveWebpageImage(DialogFragment dialogFragment) {
+ // Get the dialog.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get a handle for the file name edit text.
- EditText fileNameEditText = dialogFragment.getDialog().findViewById(R.id.file_name_edittext);
+ EditText fileNameEditText = dialog.findViewById(R.id.file_name_edittext);
// Get the file path string.
saveWebsiteImageFilePath = fileNameEditText.getText().toString();
orbotStatus = intent.getStringExtra("org.torproject.android.intent.extra.STATUS");
// If Privacy Browser is waiting on Orbot, load the website now that Orbot is connected.
- if (orbotStatus.equals("ON") && waitingForOrbot) {
+ if ((orbotStatus != null) && orbotStatus.equals("ON") && waitingForOrbot) {
// Reset the waiting for Orbot status.
waitingForOrbot = false;
bookmarksListView.setOnItemClickListener((parent, view, position, id) -> {
// Convert the id from long to int to match the format of the bookmarks database.
- int databaseID = (int) id;
+ int databaseId = (int) id;
+
+ // Get the bookmark cursor for this ID.
+ Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseId);
- // Get the bookmark cursor for this ID and move it to the first row.
- Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseID);
+ // Move the bookmark cursor to the first row.
bookmarkCursor.moveToFirst();
// Act upon the bookmark according to the type.
// Save the current folder name, which is used in `onSaveEditBookmarkFolder()`.
oldFolderNameString = bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME));
- // Show the edit bookmark folder `AlertDialog` and name the instance `@string/edit_folder`.
+ // Instantiate the edit folder bookmark dialog.
DialogFragment editBookmarkFolderDialog = EditBookmarkFolderDialog.folderDatabaseId(databaseId, currentWebView.getFavoriteOrDefaultIcon());
+
+ // Show the edit folder bookmark dialog.
editBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.edit_folder));
} else {
- // Show the edit bookmark `AlertDialog` and name the instance `@string/edit_bookmark`.
- DialogFragment editBookmarkDialog = EditBookmarkDialog.bookmarkDatabaseId(databaseId, currentWebView.getFavoriteOrDefaultIcon());
- editBookmarkDialog.show(getSupportFragmentManager(), getString(R.string.edit_bookmark));
+ // Get the bookmark cursor for this ID.
+ Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseId);
+
+ // Move the bookmark cursor to the first row.
+ bookmarkCursor.moveToFirst();
+
+ // Load the bookmark in a new tab but do not switch to the tab or close the drawer.
+ addNewTab(bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)), false);
}
// Consume the event.
bareWebView.destroy();
}
+ @Override
+ public void navigateHistory(String url, int steps) {
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, url, false, false);
+
+ // Load the history entry.
+ currentWebView.goBackOrForward(steps);
+ }
+
+ @Override
+ public void pinnedErrorGoBack() {
+ // Get the current web back forward list.
+ WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
+
+ // Get the previous entry URL.
+ String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl();
+
+ // Apply the domain settings.
+ applyDomainSettings(currentWebView, previousUrl, false, false);
+
+ // Go back.
+ currentWebView.goBack();
+ }
+
// `reloadWebsite` is used if returning from the Domains activity. Otherwise JavaScript might not function correctly if it is newly enabled.
@SuppressLint("SetJavaScriptEnabled")
private boolean applyDomainSettings(NestedScrollWebView nestedScrollWebView, String url, boolean resetTab, boolean reloadWebsite) {
}
// Apply the font size.
- if (fontSize == 0) { // Apply the default font size.
- nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
- } else { // Apply the specified font size.
- nestedScrollWebView.getSettings().setTextZoom(fontSize);
+ try { // Try the specified font size to see if it is valid.
+ if (fontSize == 0) { // Apply the default font size.
+ // Try to set the font size from the value in the app settings.
+ nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
+ } else { // Apply the font size from domain settings.
+ nestedScrollWebView.getSettings().setTextZoom(fontSize);
+ }
+ } catch (Exception exception) { // The specified font size is invalid
+ // Set the font size to be 100%
+ nestedScrollWebView.getSettings().setTextZoom(100);
}
// Set the user agent.
nestedScrollWebView.getSettings().setJavaScriptEnabled(defaultJavaScriptEnabled);
}
- // Apply the default settings.
+ // Apply the default first-party cookie setting.
cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies());
- nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
+
+ // Apply the default font size setting.
+ try {
+ // Try to set the font size from the value in the app settings.
+ nestedScrollWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
+ } catch (Exception exception) {
+ // If the app settings value is invalid, set the font size to 100%.
+ nestedScrollWebView.getSettings().setTextZoom(100);
+ }
// Apply the form data setting if the API < 26.
if (Build.VERSION.SDK_INT < 26) {
if (url.contains("&fbclid=")) {
url = url.substring(0, url.indexOf("&fbclid="));
}
+
+ // Remove `?fbadid=`.
+ if (url.contains("?fbadid=")) {
+ url = url.substring(0, url.indexOf("?fbadid="));
+ }
+
+ // Remove `&fbadid=`.
+ if (url.contains("&fbadid=")) {
+ url = url.substring(0, url.indexOf("&fbadid="));
+ }
}
// Sanitize Twitter AMP redirects.
ultraPrivacy = combinedBlocklists.get(5);
// Add the first tab.
- addNewTab("");
+ addNewTab("", true);
}
public void addTab(View view) {
// Add a new tab with a blank URL.
- addNewTab("");
+ addNewTab("", true);
}
- private void addNewTab(String url) {
+ private void addNewTab(String url, boolean moveToTab) {
// Sanitize the URL.
url = sanitizeUrl(url);
newTab.setCustomView(R.layout.tab_custom_view);
// Add the new WebView page.
- webViewPagerAdapter.addPage(newTabNumber, webViewPager, url);
+ webViewPagerAdapter.addPage(newTabNumber, webViewPager, url, moveToTab);
}
public void closeTab(View view) {
// Show the full screen video frame layout.
fullScreenVideoFrameLayout.setVisibility(View.VISIBLE);
+
+ // Disable the screen timeout while the video is playing. YouTube does this automatically, but not all other videos do.
+ fullScreenVideoFrameLayout.setKeepScreenOn(true);
}
// Exit full screen video.
// Get a handle for the full screen video frame layout.
FrameLayout fullScreenVideoFrameLayout = findViewById(R.id.full_screen_video_framelayout);
+ // Re-enable the screen timeout.
+ fullScreenVideoFrameLayout.setKeepScreenOn(false);
+
// Unset the full screen video flag.
displayingFullScreenVideo = false;
// Get the IP addresses for the host.
new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost());
- // Apply any custom domain settings if the URL was loaded by navigating history.
- if (nestedScrollWebView.getNavigatingHistory()) {
- // Reset navigating history.
- nestedScrollWebView.setNavigatingHistory(false);
-
- // Apply the domain settings.
- boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false);
-
- // Manually load the URL if the user agent has changed, which will have caused the previous URL to be reloaded.
- if (userAgentChanged) {
- loadUrl(url);
- }
- }
-
// Replace Refresh with Stop if the options menu has been created. (The first WebView typically begins loading before the menu items are instantiated.)
if (optionsMenu != null) {
// Get a handle for the refresh menu item.
tabTitleTextView.setText(R.string.new_tab);
}
} else { // The WebView has loaded a webpage.
- // Display the final URL. Getting the URL from the WebView instead of using the one provided by `onPageFinished()` makes websites like YouTube function correctly.
- urlEditText.setText(currentUrl);
+ // Update the URL edit text if it is not currently being edited.
+ if (!urlEditText.hasFocus()) {
+ // Sanitize the current URL. This removes unwanted URL elements that were added by redirects, so that they won't be included if the URL is shared.
+ String sanitizedUrl = sanitizeUrl(currentUrl);
- // Apply text highlighting to the URL.
- highlightUrlText();
+ // Display the final URL. Getting the URL from the WebView instead of using the one provided by `onPageFinished()` makes websites like YouTube function correctly.
+ urlEditText.setText(sanitizedUrl);
+
+ // Apply text highlighting to the URL.
+ highlightUrlText();
+ }
// Only populate the title text view if the tab has been fully created.
if (tab != null) {