1
0
Fork 0

Fixes #290: Integrate new Fenix architecture

master
Colin Lee 2019-01-29 13:20:29 -06:00
parent 8af55652be
commit 273f33b244
20 changed files with 361 additions and 82 deletions

View File

@ -104,6 +104,7 @@ dependencies {
implementation Deps.mozilla_concept_toolbar
implementation Deps.mozilla_browser_awesomebar
implementation Deps.mozilla_feature_downloads
implementation Deps.mozilla_browser_domains
implementation Deps.mozilla_browser_engine_gecko_nightly
implementation Deps.mozilla_browser_session
@ -116,6 +117,7 @@ dependencies {
implementation Deps.mozilla_feature_session
implementation Deps.mozilla_feature_toolbar
implementation Deps.mozilla_feature_tabs
implementation Deps.mozilla_service_fretboard
implementation Deps.mozilla_support_ktx

View File

@ -0,0 +1,24 @@
/* 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
import android.content.Context
import mozilla.components.service.fretboard.ExperimentDescriptor
const val EXPERIMENTS_JSON_FILENAME = "experiments.json"
const val EXPERIMENTS_BASE_URL = "https://settings.prod.mozaws.net/v1"
const val EXPERIMENTS_BUCKET_NAME = "main"
// TODO Change this after fenix-experiments is created
const val EXPERIMENTS_COLLECTION_NAME = "focus-experiments"
object Experiments {
val AATestDescriptor = ExperimentDescriptor("AAtest")
}
val Context.app: FenixApplication
get() = applicationContext as FenixApplication
fun Context.isInExperiment(descriptor: ExperimentDescriptor): Boolean =
app.fretboard.isInExperiment(this, descriptor)

View File

@ -5,15 +5,50 @@
package org.mozilla.fenix
import android.app.Application
import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import mozilla.components.service.fretboard.Fretboard
import mozilla.components.service.fretboard.ValuesProvider
import mozilla.components.service.fretboard.source.kinto.KintoExperimentSource
import mozilla.components.service.fretboard.storage.flatfile.FlatFileExperimentStorage
import mozilla.components.support.base.log.Log
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.base.log.sink.AndroidLogSink
import org.mozilla.fenix.components.Components
import java.io.File
class FenixApplication : Application() {
lateinit var fretboard: Fretboard
val components by lazy { Components(this) }
override fun onCreate() {
super.onCreate()
Log.addSink(AndroidLogSink())
setupCrashReporting()
loadExperiments()
}
private fun loadExperiments() {
val experimentsFile = File(filesDir, EXPERIMENTS_JSON_FILENAME)
val experimentSource = KintoExperimentSource(
EXPERIMENTS_BASE_URL, EXPERIMENTS_BUCKET_NAME, EXPERIMENTS_COLLECTION_NAME
)
fretboard = Fretboard(experimentSource, FlatFileExperimentStorage(experimentsFile),
object : ValuesProvider() {
override fun getClientId(context: Context): String {
return "10" // hardcode clientId to determine in or out of experiment
}
})
fretboard.loadExperiments()
Logger.debug("Bucket is ${fretboard.getUserBucket(this@FenixApplication)}")
Logger.debug("Experiments active: ${fretboard.getExperimentsMap(this@FenixApplication)}")
GlobalScope.launch(Dispatchers.IO) {
fretboard.updateExperiments()
}
}
private fun setupCrashReporting() {

View File

@ -1,3 +1,7 @@
/* 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
import android.app.Activity

View File

@ -1,8 +1,10 @@
/* 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.browser
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.transition.TransitionInflater
@ -10,6 +12,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.accessibility.AccessibilityManager
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_browser.*
import mozilla.components.feature.downloads.DownloadsFeature
@ -19,7 +22,6 @@ import mozilla.components.support.ktx.android.arch.lifecycle.addObservers
import org.mozilla.fenix.R
import org.mozilla.fenix.components.toolbar.ToolbarIntegration
import org.mozilla.fenix.ext.requireComponents
import androidx.coordinatorlayout.widget.CoordinatorLayout
class BrowserFragment : Fragment() {
@ -40,6 +42,7 @@ class BrowserFragment : Fragment() {
sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
}
@SuppressLint("CheckResult")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -60,17 +63,6 @@ class BrowserFragment : Fragment() {
engineView
)
lifecycle.addObserver(
ToolbarIntegration(
requireContext(),
toolbar,
requireComponents.toolbar.shippedDomainsProvider,
requireComponents.core.historyStorage
)
)
lifecycle.addObservers(sessionFeature)
// Stop toolbar from collapsing if TalkBack is enabled
val accessibilityManager = context?.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
if (accessibilityManager.isEnabled) {
@ -80,7 +72,11 @@ class BrowserFragment : Fragment() {
lifecycle.addObservers(
downloadsFeature,
sessionFeature
sessionFeature,
ToolbarIntegration(requireContext(),
toolbar,
requireComponents.toolbar.shippedDomainsProvider,
requireComponents.core.historyStorage)
)
}

View File

@ -1,3 +1,7 @@
/* 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
import android.content.Context

View File

@ -5,20 +5,15 @@
package org.mozilla.fenix.components.toolbar
import android.content.Context
import android.view.LayoutInflater
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.navigation.Navigation
import androidx.navigation.fragment.FragmentNavigator
import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.storage.HistoryStorage
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.feature.toolbar.ToolbarFeature
import mozilla.components.support.ktx.android.content.res.pxToDp
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.application
import org.mozilla.fenix.ext.components
@ -33,11 +28,6 @@ class ToolbarIntegration(
init {
toolbar.setMenuBuilder(context.components.toolbar.menuBuilder)
toolbar.browserActionMargin = toolbar.resources.pxToDp(browserActionMarginDp)
toolbar.textColor = ContextCompat.getColor(context, R.color.searchText)
toolbar.urlBoxView = LayoutInflater.from(context).inflate(R.layout.layout_url_backround, null)
toolbar.urlBoxMargin = toolbar.resources.pxToDp(urlBoxMargin)
val home = BrowserToolbar.Button(
context.resources.getDrawable(
R.drawable.ic_home,
@ -49,15 +39,6 @@ class ToolbarIntegration(
toolbar.addBrowserAction(home)
toolbar.onUrlClicked = {
val extras = FragmentNavigator.Extras.Builder().addSharedElement(
toolbar, ViewCompat.getTransitionName(toolbar)!!
).build()
Navigation.findNavController(toolbar)
.navigate(R.id.action_browserFragment_to_searchFragment, null, null, extras)
false
}
ToolbarAutocompleteFeature(toolbar).apply {
addDomainProvider(domainAutocompleteProvider)
addHistoryStorageProvider(historyStorage)

View File

@ -28,13 +28,16 @@ class HomeFragment : Fragment() {
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_home, container, false)
SessionsComponent(view.homeLayout, ActionBusFactory.get(this)).setup()
SessionsComponent(view.homeLayout, ActionBusFactory.get(this))
ActionBusFactory.get(this).logMergedObservables()
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
layoutComponents(view.homeLayout)
val searchIcon = requireComponents.search.searchEngineManager.getDefaultSearchEngine(requireContext()).let {
BitmapDrawable(resources, it.icon)
}
@ -45,7 +48,6 @@ class HomeFragment : Fragment() {
toolbar.setOnClickListener { it ->
Navigation.findNavController(it).navigate(R.id.action_homeFragment_to_searchFragment, null, null)
}
layoutComponents(homeLayout)
}
companion object {

View File

@ -7,16 +7,19 @@ package org.mozilla.fenix.home.sessions
import android.annotation.SuppressLint
import android.view.ViewGroup
import mozilla.components.browser.session.Session
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.mvi.Action
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.Change
import org.mozilla.fenix.mvi.UIComponent
import org.mozilla.fenix.mvi.ViewState
class SessionsComponent(private val container: ViewGroup, override val bus: ActionBusFactory) :
UIComponent<SessionsState, SessionsAction, SessionsChange>(bus) {
class SessionsComponent(
private val container: ViewGroup,
override val bus: ActionBusFactory,
override var initialState: SessionsState = SessionsState(emptyList())
) :
UIComponent<SessionsState, SessionsAction, SessionsChange>(bus) {
override val reducer: (SessionsState, SessionsChange) -> SessionsState = { state, change ->
when (change) {
@ -26,9 +29,17 @@ class SessionsComponent(private val container: ViewGroup, override val bus: Acti
override fun initView() = SessionsUIView(container, bus)
init {
setup()
}
@SuppressLint("CheckResult")
fun setup(): SessionsComponent {
render(reducer)
getUserInteractionEvents<SessionsAction>()
.subscribe {
Logger("SessionsComponent").debug(it.toString())
}
return this
}
}

View File

@ -1,13 +1,17 @@
/* 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.home.sessions
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID
import kotlinx.android.synthetic.main.component_sessions.*
import kotlinx.android.synthetic.main.fragment_home.*
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.TOP
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.BOTTOM
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.START
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.END
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.START
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.TOP
import org.jetbrains.anko.constraint.layout.applyConstraintSet
import org.mozilla.fenix.home.HomeFragment

View File

@ -21,6 +21,7 @@ class SessionsUIView(container: ViewGroup, bus: ActionBusFactory) :
.findViewById(R.id.session_list)
private val sessionsAdapter = SessionsAdapter()
init {
view.apply {
layoutManager = LinearLayoutManager(container.context)

View File

@ -0,0 +1,67 @@
/* 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.search
import android.annotation.SuppressLint
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.fragment_browser.*
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.mvi.Action
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.Change
import org.mozilla.fenix.mvi.Reducer
import org.mozilla.fenix.mvi.UIComponent
import org.mozilla.fenix.mvi.ViewState
class SearchComponent(
private val container: ViewGroup,
override val bus: ActionBusFactory,
private val onEditComplete: (View) -> Unit,
override var initialState: SearchState = SearchState("")
) :
UIComponent<SearchState, SearchAction, SearchChange>(bus) {
override val reducer: Reducer<SearchState, SearchChange> = { state, change ->
when (change) {
is SearchChange.Changed -> state // TODO handle state changes here
}
}
override fun initView() = SearchUIView(container, bus)
init {
setup()
}
fun getView(): BrowserToolbar = uiView.toolbar
fun editMode() = getView().editMode()
@SuppressLint("CheckResult")
fun setup(): SearchComponent {
render(reducer)
getUserInteractionEvents<SearchAction>()
.subscribe {
Logger("SearchComponent").debug(it.toString())
when (it) {
is SearchAction.EditComplete -> {
onEditComplete.invoke(getView())
}
else -> {}
}
}
return this
}
}
data class SearchState(val term: String) : ViewState
sealed class SearchAction : Action {
object UrlClicked : SearchAction()
object EditComplete : SearchAction()
}
sealed class SearchChange : Change {
object Changed : SearchChange()
}

View File

@ -1,72 +1,64 @@
/* 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.search
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_search.*
import kotlinx.android.synthetic.main.fragment_search.view.*
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
import mozilla.components.feature.awesomebar.AwesomeBarFeature
import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider
import org.mozilla.fenix.R
import org.mozilla.fenix.components.toolbar.ToolbarIntegration
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.mvi.ActionBusFactory
class SearchFragment : Fragment() {
private lateinit var awesomeBarFeature: AwesomeBarFeature
private lateinit var searchComponent: SearchComponent
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_search, container, false)
val view = inflater.inflate(R.layout.fragment_search, container, false)
searchComponent = SearchComponent(view.toolbar_wrapper, ActionBusFactory.get(this),
{ v -> transitionToBrowser(v) })
return view
}
override fun onResume() {
super.onResume()
toolbar.editMode()
searchComponent.editMode()
}
@SuppressLint("CheckResult")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
layoutComponents(view.search_layout)
lifecycle.addObserver(
ToolbarIntegration(
requireContext(),
toolbar,
ShippedDomainsProvider().also { it.initialize(requireContext()) },
requireComponents.core.historyStorage
requireContext(),
searchComponent.getView(),
ShippedDomainsProvider().also { it.initialize(requireContext()) },
requireComponents.core.historyStorage
)
)
awesomeBarFeature = AwesomeBarFeature(awesomeBar, toolbar, null, onEditComplete = ::userDidSearch)
.addClipboardProvider(requireContext(), requireComponents.useCases.sessionUseCases.loadUrl)
.addSearchProvider(
requireComponents.search.searchEngineManager.getDefaultSearchEngine(requireContext()),
requireComponents.useCases.searchUseCases.defaultSearch,
SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS)
.addSessionProvider(
requireComponents.core.sessionManager,
requireComponents.useCases.tabsUseCases.selectTab)
toolbar_wrapper.clipToOutline = false
toolbar.apply {
textColor = ContextCompat.getColor(context, R.color.searchText)
textSize = toolbarTextSizeSp
hint = context.getString(R.string.search_hint)
hintColor = ContextCompat.getColor(context, R.color.searchText)
}
}
private fun userDidSearch() {
Navigation.findNavController(toolbar).navigate(R.id.action_searchFragment_to_browserFragment, null, null)
private fun transitionToBrowser(toolbar: View) {
Navigation.findNavController(toolbar)
.navigate(R.id.action_searchFragment_to_browserFragment, null, null)
}
companion object {

View File

@ -0,0 +1,79 @@
/* 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.search
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.UNSET
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_search.*
import mozilla.components.support.base.log.logger.Logger
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.BOTTOM
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.TOP
import org.jetbrains.anko.constraint.layout.applyConstraintSet
import org.mozilla.fenix.Experiments.AATestDescriptor
import org.mozilla.fenix.isInExperiment
internal fun SearchFragment.layoutComponents(layout: ConstraintLayout) {
context?.let {
when {
it.isInExperiment(AATestDescriptor) -> {
setInExperimentConstraints(layout)
}
else -> {
setOutOfExperimentConstraints(layout)
}
}
} // we're unattached if context is null
}
internal fun SearchFragment.setInExperimentConstraints(layout: ConstraintLayout) {
Logger.debug("Loading in experiment constraints")
layout.applyConstraintSet {
toolbar_wrapper {
connect(
TOP to TOP of UNSET,
BOTTOM to TOP of pill_wrapper
)
}
awesomeBar {
connect(
TOP to TOP of PARENT_ID,
BOTTOM to TOP of toolbar_wrapper
)
}
(awesomeBar.layoutManager as? LinearLayoutManager)?.reverseLayout = true
pill_wrapper {
connect(
BOTTOM to BOTTOM of PARENT_ID
)
}
}
}
internal fun SearchFragment.setOutOfExperimentConstraints(layout: ConstraintLayout) {
Logger.debug("Loading out of experiment constraints")
layout.applyConstraintSet {
toolbar_wrapper {
connect(
TOP to TOP of PARENT_ID,
BOTTOM to TOP of UNSET
)
}
awesomeBar {
connect(
TOP to TOP of UNSET,
TOP to BOTTOM of toolbar_wrapper,
BOTTOM to TOP of pill_wrapper
)
}
(awesomeBar.layoutManager as? LinearLayoutManager)?.reverseLayout = false
pill_wrapper {
connect(
BOTTOM to BOTTOM of PARENT_ID
)
}
}
}

View File

@ -0,0 +1,72 @@
/* 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.search
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import io.reactivex.functions.Consumer
import kotlinx.android.synthetic.main.fragment_search.view.*
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.feature.awesomebar.AwesomeBarFeature
import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider
import mozilla.components.support.ktx.android.content.res.pxToDp
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.UIView
class SearchUIView(container: ViewGroup, bus: ActionBusFactory) :
UIView<SearchState>(container, bus) {
override val view: BrowserToolbar = LayoutInflater.from(container.context)
.inflate(R.layout.component_search, container, true)
.findViewById(R.id.toolbar)
private val urlBackground = LayoutInflater.from(container.context)
.inflate(R.layout.layout_url_backround, container, false)
init {
view.apply {
onUrlClicked = {
bus.emit(SearchAction::class.java, SearchAction.UrlClicked)
false
}
browserActionMargin = resources.pxToDp(browserActionMarginDp)
urlBoxView = urlBackground
urlBoxMargin = this.resources.pxToDp(urlBoxMarginDp)
textColor = ContextCompat.getColor(context, R.color.searchText)
textSize = toolbarTextSizeSp
hint = context.getString(R.string.search_hint)
hintColor = ContextCompat.getColor(context, R.color.searchText)
}
with(container.context) {
AwesomeBarFeature(container.rootView.awesomeBar, view, null,
onEditComplete = { bus.emit(SearchAction::class.java, SearchAction.EditComplete) })
.addClipboardProvider(this, components.useCases.sessionUseCases.loadUrl)
.addSearchProvider(
components.search.searchEngineManager.getDefaultSearchEngine(this),
components.useCases.searchUseCases.defaultSearch,
SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS
)
.addSessionProvider(
components.core.sessionManager,
components.useCases.tabsUseCases.selectTab
)
}
}
override fun updateView() = Consumer<SearchState> {
}
companion object {
const val toolbarTextSizeSp = 14f
const val browserActionMarginDp = 8
const val urlBoxMarginDp = 8
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<mozilla.components.browser.toolbar.BrowserToolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="8dp"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"/>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/session_list"
android:layout_width="0dp"
android:layout_height="0dp"

View File

@ -8,9 +8,10 @@
xmlns:mozac="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".search.SearchFragment">
tools:context=".search.SearchFragment"
android:id="@+id/search_layout">
<FrameLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/toolbar_wrapper"
android:layout_width="0dp"
android:layout_height="wrap_content"
@ -21,17 +22,7 @@
android:outlineProvider="paddedBounds"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<mozilla.components.browser.toolbar.BrowserToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="8dp"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true" />
</FrameLayout>
app:layout_constraintTop_toTopOf="parent"/>
<mozilla.components.browser.awesomebar.BrowserAwesomeBar
android:id="@+id/awesomeBar"

View File

@ -13,7 +13,8 @@
<fragment android:id="@+id/searchFragment" android:name="org.mozilla.fenix.search.SearchFragment"
android:label="fragment_search" tools:layout="@layout/fragment_search">
<action android:id="@+id/action_searchFragment_to_browserFragment" app:destination="@id/browserFragment"/>
<action android:id="@+id/action_searchFragment_to_browserFragment" app:destination="@id/browserFragment"
app:popUpTo="@id/homeFragment"/>
</fragment>
<fragment android:id="@+id/browserFragment" android:name="org.mozilla.fenix.browser.BrowserFragment"

View File

@ -73,6 +73,8 @@ object Deps {
const val mozilla_feature_prompts = "org.mozilla.components:feature-prompts:${Versions.mozilla_android_components}"
const val mozilla_feature_toolbar = "org.mozilla.components:feature-toolbar:${Versions.mozilla_android_components}"
const val mozilla_service_fretboard = "org.mozilla.components:service-fretboard:${Versions.mozilla_android_components}"
const val mozilla_lib_crash = "org.mozilla.components:lib-crash:${Versions.mozilla_android_components}"
const val mozilla_support_ktx = "org.mozilla.components:support-ktx:${Versions.mozilla_android_components}"