diff --git a/app/src/main/java/org/mozilla/fenix/components/Utilities.kt b/app/src/main/java/org/mozilla/fenix/components/Utilities.kt
index a6ecfb2e7e..20f46417af 100644
--- a/app/src/main/java/org/mozilla/fenix/components/Utilities.kt
+++ b/app/src/main/java/org/mozilla/fenix/components/Utilities.kt
@@ -11,6 +11,7 @@ import mozilla.components.feature.intent.processing.TabIntentProcessor
import mozilla.components.feature.search.SearchUseCases
import mozilla.components.feature.session.SessionUseCases
import org.mozilla.fenix.test.Mockable
+import org.mozilla.fenix.utils.ClipboardHandler
/**
* Component group for miscellaneous components.
@@ -39,4 +40,8 @@ class Utilities(
val customTabIntentProcessor by lazy {
CustomTabIntentProcessor(sessionManager, sessionUseCases.loadUrl, context.resources)
}
+
+ val clipboardHandler by lazy {
+ ClipboardHandler(context)
+ }
}
diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt
index 8ac9c48021..0fd81157ed 100644
--- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt
+++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt
@@ -1,9 +1,9 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
package org.mozilla.fenix.components.toolbar
-import android.content.ClipData
-import android.content.ClipDescription.MIMETYPE_TEXT_PLAIN
-import android.content.ClipboardManager
-import android.content.Context.CLIPBOARD_SERVICE
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -54,7 +54,7 @@ class BrowserToolbarView(
val isCustomTabSession = customTabSession != null
view.setOnUrlLongClickListener {
- val clipboard = view.context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
+ val clipboard = view.context.components.utils.clipboardHandler
val customView = LayoutInflater.from(view.context).inflate(R.layout.browser_toolbar_popup_window, null)
val popupWindow = PopupWindow(customView,
LinearLayout.LayoutParams.WRAP_CONTENT,
@@ -64,22 +64,22 @@ class BrowserToolbarView(
popupWindow.elevation = view.context.dimen(R.dimen.mozac_browser_menu_elevation).toFloat()
- customView.paste.isVisible = clipboard.containsText() && !isCustomTabSession
- customView.paste_and_go.isVisible = clipboard.containsText() && !isCustomTabSession
+ customView.paste.isVisible = !clipboard.url.isNullOrEmpty() && !isCustomTabSession
+ customView.paste_and_go.isVisible = !clipboard.url.isNullOrEmpty() && !isCustomTabSession
customView.copy.setOnClickListener {
popupWindow.dismiss()
- clipboard.primaryClip = ClipData.newPlainText("Text", view.url.toString())
+ clipboard.text = view.url.toString()
}
customView.paste.setOnClickListener {
popupWindow.dismiss()
- interactor.onBrowserToolbarPaste(clipboard.primaryClip?.getItemAt(0)?.text.toString())
+ interactor.onBrowserToolbarPaste(clipboard.text!!)
}
customView.paste_and_go.setOnClickListener {
popupWindow.dismiss()
- interactor.onBrowserToolbarPasteAndGo(clipboard.primaryClip?.getItemAt(0)?.text.toString())
+ interactor.onBrowserToolbarPasteAndGo(clipboard.text!!)
}
popupWindow.showAsDropDown(view, view.context.dimen(R.dimen.context_menu_x_offset), 0, Gravity.START)
@@ -162,10 +162,6 @@ class BrowserToolbarView(
// Intentionally leaving this as a stub for now since we don't actually want to update currently
}
- private fun ClipboardManager.containsText(): Boolean {
- return (primaryClipDescription?.hasMimeType(MIMETYPE_TEXT_PLAIN) ?: false && primaryClip?.itemCount != 0)
- }
-
companion object {
private const val TOOLBAR_ELEVATION = 16
private const val PROGRESS_BOTTOM = 0
diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt
index 11174b269e..88713747c9 100644
--- a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt
+++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt
@@ -37,6 +37,7 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
+import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getColorFromAttr
import org.mozilla.fenix.ext.getSpannable
import org.mozilla.fenix.ext.requireComponents
@@ -116,6 +117,7 @@ class SearchFragment : Fragment(), BackHandler {
)
awesomeBarView = AwesomeBarView(view.search_layout, searchInteractor)
+
toolbarView = ToolbarView(
view.toolbar_component_wrapper,
searchInteractor,
@@ -129,6 +131,7 @@ class SearchFragment : Fragment(), BackHandler {
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
+ @SuppressWarnings("LongMethod")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -198,12 +201,22 @@ class SearchFragment : Fragment(), BackHandler {
searchInteractor.turnOnStartedTyping()
}
+ fill_link_from_clipboard.setOnClickListener {
+ (activity as HomeActivity)
+ .openToBrowserAndLoad(
+ searchTermOrURL = requireContext().components.utils.clipboardHandler.url ?: "",
+ newTab = searchStore.state.session == null,
+ from = BrowserDirection.FromSearch
+ )
+ }
+
consumeFrom(searchStore) {
awesomeBarView.update(it)
toolbarView.update(it)
updateSearchEngineIcon(it)
updateSearchShortuctsIcon(it)
updateSearchWithLabel(it)
+ updateClipboardSuggestion(it, requireContext().components.utils.clipboardHandler.url)
}
startPostponedEnterTransition()
@@ -231,6 +244,8 @@ class SearchFragment : Fragment(), BackHandler {
toolbarView.view.requestFocus()
}
+ updateClipboardSuggestion(searchStore.state, requireContext().components.utils.clipboardHandler.url)
+
permissionDidUpdate = false
(activity as AppCompatActivity).supportActionBar?.hide()
}
@@ -260,10 +275,18 @@ class SearchFragment : Fragment(), BackHandler {
}
private fun updateSearchWithLabel(searchState: SearchFragmentState) {
- searchWithShortcuts.visibility =
+ search_with_shortcuts.visibility =
if (searchState.showShortcutEnginePicker) View.VISIBLE else View.GONE
}
+ private fun updateClipboardSuggestion(searchState: SearchFragmentState, clipboardUrl: String?) {
+ fill_link_from_clipboard.visibility =
+ if (searchState.showClipboardSuggestions && searchState.query.isEmpty() && !clipboardUrl.isNullOrEmpty())
+ View.VISIBLE else View.GONE
+
+ clipboard_url.text = clipboardUrl
+ }
+
private fun updateSearchShortuctsIcon(searchState: SearchFragmentState) {
with(requireContext()) {
val showShortcuts = searchState.showShortcutEnginePicker
diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt b/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt
index e82bdbfe43..c018f39d79 100644
--- a/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt
+++ b/app/src/main/java/org/mozilla/fenix/search/SearchLayouts.kt
@@ -63,7 +63,7 @@ internal fun SearchFragment.setOutOfExperimentConstraints(layout: ConstraintLayo
BOTTOM to TOP of UNSET
)
}
- searchWithShortcuts {
+ fill_link_from_clipboard {
connect(
TOP to BOTTOM of toolbar_wrapper
)
@@ -71,7 +71,7 @@ internal fun SearchFragment.setOutOfExperimentConstraints(layout: ConstraintLayo
awesomeBar {
connect(
TOP to TOP of UNSET,
- TOP to BOTTOM of searchWithShortcuts,
+ TOP to BOTTOM of search_with_shortcuts,
BOTTOM to TOP of pillWrapper
)
}
diff --git a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt
index 1c34481369..bb59f7e697 100644
--- a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt
+++ b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt
@@ -16,7 +16,6 @@ import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.session.Session
import mozilla.components.concept.engine.EngineSession
import mozilla.components.feature.awesomebar.provider.BookmarksStorageSuggestionProvider
-import mozilla.components.feature.awesomebar.provider.ClipboardSuggestionProvider
import mozilla.components.feature.awesomebar.provider.HistoryStorageSuggestionProvider
import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider
import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider
@@ -80,7 +79,6 @@ class AwesomeBarView(
override val containerView: View?
get() = container
- private val clipboardSuggestionProvider: ClipboardSuggestionProvider
private val sessionProvider: SessionSuggestionProvider
private val historyStorageProvider: HistoryStorageSuggestionProvider
private val shortcutsEnginePickerProvider: ShortcutsSuggestionProvider
@@ -118,13 +116,6 @@ class AwesomeBarView(
val draw = getDrawable(R.drawable.ic_link)!!
draw.setColorFilter(primaryTextColor, SRC_IN)
- clipboardSuggestionProvider = ClipboardSuggestionProvider(
- this,
- loadUrlUseCase,
- draw.toBitmap(),
- getString(R.string.awesomebar_clipboard_title)
- )
-
sessionProvider =
SessionSuggestionProvider(
components.core.sessionManager,
@@ -189,10 +180,6 @@ class AwesomeBarView(
)
}
- if (state.showClipboardSuggestions) {
- view.addProviders(clipboardSuggestionProvider)
- }
-
if (state.showHistorySuggestions) {
view.addProviders(historyStorageProvider)
}
diff --git a/app/src/main/java/org/mozilla/fenix/utils/ClipboardHandler.kt b/app/src/main/java/org/mozilla/fenix/utils/ClipboardHandler.kt
new file mode 100644
index 0000000000..9078efd596
--- /dev/null
+++ b/app/src/main/java/org/mozilla/fenix/utils/ClipboardHandler.kt
@@ -0,0 +1,44 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.utils
+
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import mozilla.components.support.utils.WebURLFinder
+
+private const val MIME_TYPE_TEXT_PLAIN = "text/plain"
+
+class ClipboardHandler(context: Context) {
+ private val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+
+ var text: String?
+ get() {
+ if (clipboard.isPrimaryClipEmpty() ||
+ !clipboard.isPrimaryClipPlainText()) {
+ return null
+ }
+
+ return clipboard.firstPrimaryClipItem?.text.toString()
+ }
+
+ set(value) {
+ clipboard.primaryClip = ClipData.newPlainText("Text", value)
+ }
+
+ val url: String?
+ get() {
+ val finder = WebURLFinder(text)
+ return finder.bestWebURL()
+ }
+
+ private fun ClipboardManager.isPrimaryClipPlainText() =
+ primaryClipDescription?.hasMimeType(MIME_TYPE_TEXT_PLAIN) ?: false
+
+ private fun ClipboardManager.isPrimaryClipEmpty() = primaryClip?.itemCount == 0
+
+ private val ClipboardManager.firstPrimaryClipItem: ClipData.Item?
+ get() = primaryClip?.getItemAt(0)
+}
diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml
index 7b49ff27ad..e4795b071c 100644
--- a/app/src/main/res/layout/fragment_search.xml
+++ b/app/src/main/res/layout/fragment_search.xml
@@ -43,11 +43,66 @@
+
+
+
+
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@id/fill_link_from_clipboard" />
14sp
+
+