private lateinit var navigationForwardMenuItem: MenuItem
private lateinit var navigationHistoryMenuItem: MenuItem
private lateinit var navigationRequestsMenuItem: MenuItem
+ private lateinit var navigationScrollToBottomMenuItem: MenuItem
private lateinit var navigationView: NavigationView
private lateinit var optionsAddOrEditDomainMenuItem: MenuItem
private lateinit var optionsBlockAllThirdPartyRequestsMenuItem: MenuItem
private var orbotStatusBroadcastReceiver: BroadcastReceiver? = null
private var reapplyAppSettingsOnRestart = false
private var reapplyDomainSettingsOnRestart = false
- private var restartTime = Date(0)
private var sanitizeAmpRedirects = false
private var sanitizeTrackingQueries = false
private var savedProxyMode: String? = null
// Get handles for the navigation menu items.
navigationBackMenuItem = navigationMenu.findItem(R.id.back)
navigationForwardMenuItem = navigationMenu.findItem(R.id.forward)
+ navigationScrollToBottomMenuItem = navigationMenu.findItem(R.id.scroll_to_bottom)
navigationHistoryMenuItem = navigationMenu.findItem(R.id.history)
navigationRequestsMenuItem = navigationMenu.findItem(R.id.requests)
// Run the default commands.
super.onNewIntent(intent)
+ // Close the navigation drawer if it is open.
+ if (drawerLayout.isDrawerVisible(GravityCompat.START))
+ drawerLayout.closeDrawer(GravityCompat.START)
+
+ // Close the bookmarks drawer if it is open.
+ if (drawerLayout.isDrawerVisible(GravityCompat.END))
+ drawerLayout.closeDrawer(GravityCompat.END)
+
// Get the information from the intent.
val intentAction = intent.action
val intentUriData = intent.data
// Make it so.
loadUrl(currentWebView!!, url!!)
}
-
- // Close the navigation drawer if it is open.
- if (drawerLayout.isDrawerVisible(GravityCompat.START))
- drawerLayout.closeDrawer(GravityCompat.START)
-
- // Close the bookmarks drawer if it is open.
- if (drawerLayout.isDrawerVisible(GravityCompat.END))
- drawerLayout.closeDrawer(GravityCompat.END)
}
} else { // The app has been restarted.
- // If the new intent will open a new tab, set the saved tab position to be the size of the saved state array list.
- // The tab position is 0 based, meaning the new tab will be the tab position that is restored.
- if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch)
- savedTabPosition = savedStateArrayList!!.size
-
// Replace the intent that started the app with this one. This will load the tab after the others have been restored.
setIntent(intent)
}
}
}
+ R.id.scroll_to_bottom -> { // Scroll to Bottom.
+ // Check if the WebView is scrolled to the top.
+ if (currentWebView!!.scrollY == 0) { // The WebView is at the top; scroll to the bottom. Using a large Y number is more efficient than trying to calculate the exact WebView length.
+ currentWebView!!.scrollTo(0, 1_000_000_000)
+ } else { // The WebView is not at the top; scroll to the top.
+ currentWebView!!.scrollTo(0, 0)
+ }
+ }
+
R.id.history -> { // History.
// Instantiate the URL history dialog.
val urlHistoryDialogFragment: DialogFragment = UrlHistoryDialog.loadBackForwardList(currentWebView!!.webViewFragmentId)
true
}
+ // Add a Share URL entry.
+ contextMenu.add(R.string.share_url).setOnMenuItemClickListener {
+ // Create the share intent.
+ val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+ // Add the URL to the intent.
+ shareUrlIntent.putExtra(Intent.EXTRA_TEXT, linkUrl)
+
+ // Set the MIME type.
+ shareUrlIntent.type = "text/plain"
+
+ // Set the intent to open in a new task.
+ shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ //Make it so.
+ startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+ // Consume the event.
+ true
+ }
+
// Add an empty cancel entry, which by default closes the context menu.
contextMenu.add(R.string.cancel)
}
true
}
+ // Add a Share URL entry.
+ contextMenu.add(R.string.share_url).setOnMenuItemClickListener {
+ // Create the share intent.
+ val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+ // Add the URL to the intent.
+ shareUrlIntent.putExtra(Intent.EXTRA_TEXT, imageUrl)
+
+ // Set the MIME type.
+ shareUrlIntent.type = "text/plain"
+
+ // Set the intent to open in a new task.
+ shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ //Make it so.
+ startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+ // Consume the event.
+ true
+ }
+
// Add an empty cancel entry, which by default closes the context menu.
contextMenu.add(R.string.cancel)
}
true
}
+ // Add a Share Image entry.
+ contextMenu.add(R.string.share_image).setOnMenuItemClickListener {
+ // Create the share intent.
+ val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+ // Add the URL to the intent.
+ shareUrlIntent.putExtra(Intent.EXTRA_TEXT, imageUrl)
+
+ // Set the MIME type.
+ shareUrlIntent.type = "text/plain"
+
+ // Set the intent to open in a new task.
+ shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ //Make it so.
+ startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+ // Consume the event.
+ true
+ }
+
// Add a copy URL entry.
contextMenu.add(R.string.copy_url).setOnMenuItemClickListener {
// Save the link URL in a clip data.
true
}
+ // Add a Share URL entry.
+ contextMenu.add(R.string.share_url).setOnMenuItemClickListener {
+ // Create the share intent.
+ val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+ // Add the URL to the intent.
+ shareUrlIntent.putExtra(Intent.EXTRA_TEXT, linkUrl)
+
+ // Set the MIME type.
+ shareUrlIntent.type = "text/plain"
+
+ // Set the intent to open in a new task.
+ shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ //Make it so.
+ startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+ // Consume the event.
+ true
+ }
+
// Add an empty cancel entry, which by default closes the context menu.
contextMenu.add(R.string.cancel)
}
// Add the first tab.
addNewTab("", false)
} else { // The activity has been restarted with a saved state.
- // Set the current restart time.
- restartTime = Date()
-
// Restore each tab.
for (i in savedStateArrayList!!.indices) {
// Add a new tab.
savedStateArrayList = null
savedNestedScrollWebViewStateArrayList = null
- // Restore the selected tab position.
- if (savedTabPosition == 0) { // The first tab is selected.
- // Set the first page as the current WebView.
- setCurrentWebView(0)
- } else { // The first tab is not selected.
- // Select the tab when the layout has finished populating.
- tabLayout.post {
- // Get a handle for the tab.
- val tab = tabLayout.getTabAt(savedTabPosition)!!
-
- // Select the tab.
- tab.select()
- }
- }
-
// Get the intent that started the app.
val intent = intent
val isWebSearch = (intentAction != null) && (intentAction == Intent.ACTION_WEB_SEARCH)
// Only process the URI if it contains data or it is a web search. If the user pressed the desktop icon after the app was already running the URI will be null.
- if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch) {
+ if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch) { // A new tab is being loaded.
// Get the URL string.
val urlString = if (isWebSearch) { // The intent is a web search.
// Sanitize the search input.
// Make it so.
loadUrl(currentWebView!!, urlString)
}
+ } else { // A new tab is not being loaded.
+ // Restore the selected tab position.
+ if (savedTabPosition == 0) { // The first tab is selected.
+ // Set the first page as the current WebView.
+ setCurrentWebView(0)
+ } else { // The first tab is not selected.
+ // Select the tab when the layout has finished populating.
+ tabLayout.post {
+ // Get a handle for the tab.
+ val tab = tabLayout.getTabAt(savedTabPosition)!!
+
+ // Select the tab.
+ tab.select()
+ }
+ }
}
}
}
// Only display the view SSL certificate dialog if the current WebView is not null.
// This can happen if the tab is programmatically reselected while the app is being restarted and is not yet populated.
if (currentWebView != null) {
- // Calculate the milliseconds since the last restart. This can be replaced by the simpler LocalDateTime once the minimum API >= 26.
- val millisecondsSinceLastRestart = Date().time - restartTime.time
-
- // Only display the SSL certificate dialog if it has been at least 3 seconds since the last restart as deep restarts sometimes end up selecting a tab twice.
- if (millisecondsSinceLastRestart > 3000) {
- // Instantiate the View SSL Certificate dialog.
- val viewSslCertificateDialogFragment: DialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView!!.webViewFragmentId, currentWebView!!.getFavoriteIcon())
+ // Instantiate the View SSL Certificate dialog.
+ val viewSslCertificateDialogFragment: DialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView!!.webViewFragmentId, currentWebView!!.getFavoriteIcon())
- // Display the View SSL Certificate dialog.
- viewSslCertificateDialogFragment.show(supportFragmentManager, getString(R.string.view_ssl_certificate))
- }
+ // Display the View SSL Certificate dialog.
+ viewSslCertificateDialogFragment.show(supportFragmentManager, getString(R.string.view_ssl_certificate))
}
}
})
if (newState == DrawerLayout.STATE_SETTLING || newState == DrawerLayout.STATE_DRAGGING) { // A drawer is opening or closing.
// Update the navigation menu items if the WebView is not null.
if (currentWebView != null) {
+ // Set the enabled status of the menu items.
navigationBackMenuItem.isEnabled = currentWebView!!.canGoBack()
navigationForwardMenuItem.isEnabled = currentWebView!!.canGoForward()
+ navigationScrollToBottomMenuItem.isEnabled = (currentWebView!!.canScrollVertically(-1) || currentWebView!!.canScrollVertically(1))
navigationHistoryMenuItem.isEnabled = currentWebView!!.canGoBack() || currentWebView!!.canGoForward()
+
+ // Update the scroll menu item.
+ if (currentWebView!!.scrollY == 0) { // The WebView is scrolled to the top.
+ // Set the title.
+ navigationScrollToBottomMenuItem.title = getString(R.string.scroll_to_bottom)
+
+ // Set the icon.
+ navigationScrollToBottomMenuItem.icon = AppCompatResources.getDrawable(applicationContext, R.drawable.move_down_enabled)
+ } else { // The WebView is not scrolled to the top.
+ // Set the title.
+ navigationScrollToBottomMenuItem.title = getString(R.string.scroll_to_top)
+
+ // Set the icon.
+ navigationScrollToBottomMenuItem.icon = AppCompatResources.getDrawable(applicationContext, R.drawable.move_up_enabled)
+ }
+
+ // Display the number of blocked requests.
navigationRequestsMenuItem.title = getString(R.string.requests) + " - " + currentWebView!!.getRequestsCount(BLOCKED_REQUESTS)
// Hide the keyboard (if displayed).
} else { // Load the URL.
loadUrl(nestedScrollWebView, urlToLoadString!!)
}
-
- // Reset the intent. This prevents a duplicate tab from being created on a subsequent restart if loading an link from a new intent on restart.
- // For example, this prevents a duplicate tab if a link is loaded from the Guide after changing the theme in the guide and then changing the theme again in the main activity.
- intent = Intent()
} else { // This is not the first tab.
// Load the URL.
loadUrl(nestedScrollWebView, urlString)