summaryrefslogtreecommitdiffstats
path: root/mobile/android/android-components/samples/toolbar
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/android-components/samples/toolbar')
-rw-r--r--mobile/android/android-components/samples/toolbar/build.gradle57
-rw-r--r--mobile/android/android-components/samples/toolbar/lint.xml12
-rw-r--r--mobile/android/android-components/samples/toolbar/proguard-rules.pro21
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/AndroidManifest.xml29
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/ic_launcher-web.pngbin0 -> 5650 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/SampleToolbarHelpers.kt148
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt539
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/drawable/fenix_url_background.xml13
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/drawable/focus_background.xml11
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_background.xml8
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_progress.xml8
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/layout/activity_toolbar.xml23
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/layout/focus_blocking_switch.xml76
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/layout/item_toolbar_configuration.xml15
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher.xml8
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml8
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 862 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_foreground.pngbin0 -> 295 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 2590 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 733 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_foreground.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 1737 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 1177 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_foreground.pngbin0 -> 403 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 3748 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 1736 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.pngbin0 -> 716 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 6057 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 2137 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.pngbin0 -> 1092 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 8695 bytes
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/values/colors.xml7
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/values/dimens.xml8
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/values/ic_launcher_background.xml8
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/values/strings.xml9
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/xml/backup_rules.xml8
-rw-r--r--mobile/android/android-components/samples/toolbar/src/main/res/xml/data_extraction_rules.xml9
37 files changed, 1025 insertions, 0 deletions
diff --git a/mobile/android/android-components/samples/toolbar/build.gradle b/mobile/android/android-components/samples/toolbar/build.gradle
new file mode 100644
index 0000000000..896f3c77f1
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/build.gradle
@@ -0,0 +1,57 @@
+/* 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/. */
+
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+android {
+ defaultConfig {
+ applicationId "org.mozilla.samples.toolbar"
+ minSdkVersion config.minSdkVersion
+ compileSdk config.compileSdkVersion
+ targetSdkVersion config.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ buildFeatures {
+ viewBinding true
+ }
+
+ namespace 'org.mozilla.samples.toolbar'
+}
+
+
+dependencies {
+ implementation project(':concept-engine')
+ implementation project(':concept-menu')
+ implementation project(':browser-toolbar')
+ implementation project(':browser-menu')
+ implementation project(':browser-menu2')
+ implementation project(':browser-domains')
+
+ implementation project(':ui-colors')
+ implementation project(':ui-tabcounter')
+ implementation project(':ui-icons')
+
+ implementation project(':feature-toolbar')
+
+ implementation project(':support-ktx')
+
+ implementation project(':support-utils')
+
+ implementation ComponentsDependencies.kotlin_coroutines
+
+ implementation ComponentsDependencies.androidx_appcompat
+ implementation ComponentsDependencies.androidx_recyclerview
+}
diff --git a/mobile/android/android-components/samples/toolbar/lint.xml b/mobile/android/android-components/samples/toolbar/lint.xml
new file mode 100644
index 0000000000..33cf423701
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/lint.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<lint>
+ <issue id="IconMissingDensityFolder" severity="ignore">
+ <!-- Suppress lint warnings on mdpi -->
+ <ignore path="src/debug/res/drawable-mdpi"/>
+ </issue>
+
+ <issue id="GoogleAppIndexingWarning" severity="ignore" />
+</lint> \ No newline at end of file
diff --git a/mobile/android/android-components/samples/toolbar/proguard-rules.pro b/mobile/android/android-components/samples/toolbar/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/mobile/android/android-components/samples/toolbar/src/main/AndroidManifest.xml b/mobile/android/android-components/samples/toolbar/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..71bbaeb7d9
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ android:allowBackup="true"
+ android:fullBackupContent="@xml/backup_rules"
+ android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.AppCompat.NoActionBar"
+ android:dataExtractionRules="@xml/data_extraction_rules"
+ tools:targetApi="s"
+ tools:ignore="DataExtractionRules">
+ <activity android:name=".ToolbarActivity" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/ic_launcher-web.png b/mobile/android/android-components/samples/toolbar/src/main/ic_launcher-web.png
new file mode 100644
index 0000000000..b8f772f66a
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/ic_launcher-web.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/SampleToolbarHelpers.kt b/mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/SampleToolbarHelpers.kt
new file mode 100644
index 0000000000..7b98f77f80
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/SampleToolbarHelpers.kt
@@ -0,0 +1,148 @@
+/* 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.samples.toolbar
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.graphics.Canvas
+import android.graphics.drawable.ClipDrawable
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.core.content.res.ResourcesCompat
+import androidx.recyclerview.widget.RecyclerView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+// Code needed for assembling the sample application - but not needed to actually explain the toolbar
+
+enum class ToolbarConfiguration(val label: String) {
+ DEFAULT("Default"),
+ FOCUS_TABLET("Firefox Focus (Tablet)"),
+ FOCUS_PHONE("Firefox Focus (Phone)"),
+ CUSTOM_MENU("Custom Menu"),
+ PRIVATE_MODE("Private Mode"),
+ FENIX("Fenix"),
+ FENIX_CUSTOMTAB("Fenix (Custom Tab)"),
+}
+
+class ConfigurationAdapter(
+ private val configuration: ToolbarConfiguration,
+) : RecyclerView.Adapter<ConfigurationViewHolder>() {
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ConfigurationViewHolder {
+ val view = LayoutInflater.from(parent.context).inflate(R.layout.item_toolbar_configuration, parent, false)
+ return ConfigurationViewHolder(view as TextView)
+ }
+
+ override fun getItemCount() = ToolbarConfiguration.values().size
+
+ override fun onBindViewHolder(holder: ConfigurationViewHolder, position: Int) {
+ val item = ToolbarConfiguration.values()[position]
+ holder.labelView.text = item.label
+
+ holder.labelView.setOnClickListener {
+ (it.context as Activity).finish()
+
+ val intent = Intent(it.context, ToolbarActivity::class.java)
+ intent.putExtra(Extra.TOOLBAR_LABEL, item.label)
+ it.context.startActivity(intent)
+ }
+
+ if (item == configuration) {
+ holder.labelView.setBackgroundResource(R.color.selected_configuration)
+ }
+ }
+}
+
+class ConfigurationViewHolder(val labelView: TextView) : RecyclerView.ViewHolder(labelView)
+
+fun getToolbarConfiguration(intent: Intent): ToolbarConfiguration {
+ val label = intent.extras?.getString(Extra.TOOLBAR_LABEL) ?: ToolbarConfiguration.DEFAULT.label
+
+ ToolbarConfiguration.values().forEach {
+ if (label == it.label) {
+ return it
+ }
+ }
+
+ return ToolbarConfiguration.DEFAULT
+}
+
+object Extra {
+ internal const val TOOLBAR_LABEL = "toolbar_label"
+}
+
+/**
+ * A custom view to be drawn behind the URL and page actions. Acts as a custom progress view.
+ */
+class UrlBoxProgressView(
+ context: Context,
+) : View(context) {
+ var progress: Int = 0
+ set(value) {
+ // We clip the background and progress drawable based on the new progress:
+ //
+ // progress
+ // v
+ // +---------------------+-------------------+
+ // | background drawable | progress drawable |
+ // +---------------------+-------------------+
+ //
+ // The drawable is clipped completely and not visible when the level is 0 and fully
+ // revealed when the level is 10,000.
+ backgroundDrawable.level = LEVEL_STEP_SIZE * (MAX_PROGRESS - value)
+ progressDrawable.level = MAX_LEVEL - backgroundDrawable.level
+ field = value
+ invalidate() // Force redraw
+
+ // If the progress is 100% then we want to go back to 0 to hide the progress drawable
+ // again. However we want to show the full progress bar briefly so we wait 250ms before
+ // going back to 0.
+ if (value == MAX_PROGRESS) {
+ CoroutineScope(Dispatchers.Main).launch {
+ delay(PROGRESS_VISIBLE_DELAY_MS)
+ progress = 0
+ }
+ }
+ }
+
+ private var backgroundDrawable = ClipDrawable(
+ ResourcesCompat.getDrawable(resources, R.drawable.sample_url_background, context.theme),
+ Gravity.END,
+ ClipDrawable.HORIZONTAL,
+ ).apply {
+ level = MAX_LEVEL
+ }
+
+ private var progressDrawable = ClipDrawable(
+ ResourcesCompat.getDrawable(resources, R.drawable.sample_url_progress, context.theme),
+ Gravity.START,
+ ClipDrawable.HORIZONTAL,
+ ).apply {
+ level = 0
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ backgroundDrawable.setBounds(0, 0, w, h)
+ progressDrawable.setBounds(0, 0, w, h)
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ backgroundDrawable.draw(canvas)
+ progressDrawable.draw(canvas)
+ }
+
+ companion object {
+ private const val MAX_PROGRESS = 100
+ private const val PROGRESS_VISIBLE_DELAY_MS = 250L
+ private const val LEVEL_STEP_SIZE = 100
+ private const val MAX_LEVEL = 10000
+ }
+}
diff --git a/mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt b/mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt
new file mode 100644
index 0000000000..58dbb8a312
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt
@@ -0,0 +1,539 @@
+/* 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.samples.toolbar
+
+import android.content.res.Resources
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.annotation.DrawableRes
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.core.content.res.ResourcesCompat
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import mozilla.components.browser.domains.autocomplete.CustomDomainsProvider
+import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
+import mozilla.components.browser.menu.BrowserMenu
+import mozilla.components.browser.menu.BrowserMenuBuilder
+import mozilla.components.browser.menu.BrowserMenuItem
+import mozilla.components.browser.menu.ext.asCandidateList
+import mozilla.components.browser.menu.item.BrowserMenuItemToolbar
+import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
+import mozilla.components.browser.menu2.BrowserMenuController
+import mozilla.components.browser.toolbar.BrowserToolbar
+import mozilla.components.browser.toolbar.display.DisplayToolbar
+import mozilla.components.concept.menu.Side
+import mozilla.components.concept.menu.candidate.DividerMenuCandidate
+import mozilla.components.concept.menu.candidate.DrawableMenuIcon
+import mozilla.components.concept.menu.candidate.NestedMenuCandidate
+import mozilla.components.concept.menu.candidate.TextMenuCandidate
+import mozilla.components.concept.toolbar.Toolbar
+import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
+import mozilla.components.support.ktx.android.content.res.resolveAttribute
+import mozilla.components.support.ktx.android.view.hideKeyboard
+import mozilla.components.support.ktx.util.URLStringUtils
+import mozilla.components.ui.tabcounter.TabCounter
+import org.mozilla.samples.toolbar.databinding.ActivityToolbarBinding
+import mozilla.components.browser.menu.R as menuR
+import mozilla.components.browser.toolbar.R as toolbarR
+import mozilla.components.ui.colors.R as colorsR
+import mozilla.components.ui.icons.R as iconsR
+
+/**
+ * This sample application shows how to use and customize the browser-toolbar component.
+ */
+@Suppress("LargeClass")
+class ToolbarActivity : AppCompatActivity() {
+ private val shippedDomainsProvider = ShippedDomainsProvider()
+ private val customDomainsProvider = CustomDomainsProvider()
+ private lateinit var binding: ActivityToolbarBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityToolbarBinding.inflate(layoutInflater)
+
+ shippedDomainsProvider.initialize(this)
+ customDomainsProvider.initialize(this)
+
+ setContentView(binding.root)
+
+ val configuration = getToolbarConfiguration(intent)
+
+ when (configuration) {
+ ToolbarConfiguration.DEFAULT -> setupDefaultToolbar()
+ ToolbarConfiguration.FOCUS_TABLET -> setupFocusTabletToolbar()
+ ToolbarConfiguration.FOCUS_PHONE -> setupFocusPhoneToolbar()
+ ToolbarConfiguration.CUSTOM_MENU -> setupCustomMenu()
+ ToolbarConfiguration.PRIVATE_MODE -> setupDefaultToolbar(private = true)
+ ToolbarConfiguration.FENIX -> setupFenixToolbar()
+ ToolbarConfiguration.FENIX_CUSTOMTAB -> setupFenixCustomTabToolbar()
+ }
+
+ val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
+ recyclerView.adapter = ConfigurationAdapter(configuration)
+ recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
+
+ ToolbarAutocompleteFeature(binding.toolbar).apply {
+ updateAutocompleteProviders(
+ providers = listOf(shippedDomainsProvider, customDomainsProvider),
+ refreshAutocomplete = false,
+ )
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+
+ binding.toolbar.hideKeyboard()
+ }
+
+ /**
+ * A very simple toolbar with mostly default values.
+ */
+ private fun setupDefaultToolbar(private: Boolean = false) {
+ binding.toolbar.setBackgroundColor(
+ ContextCompat.getColor(this, colorsR.color.photonBlue80),
+ )
+
+ binding.toolbar.private = private
+
+ binding.toolbar.url = "https://www.mozilla.org/en-US/firefox/"
+ }
+
+ /**
+ * A toolbar that looks like Firefox Focus on tablets.
+ */
+ private fun setupFocusTabletToolbar() {
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Use the iconic gradient background
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val background = ContextCompat.getDrawable(this, R.drawable.focus_background)
+ binding.toolbar.background = background
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Add "back" and "forward" navigation actions
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val back = BrowserToolbar.Button(
+ resources.getThemedDrawable(iconsR.drawable.mozac_ic_back_24)!!,
+ "Back",
+ ) {
+ simulateReload()
+ }
+
+ binding.toolbar.addNavigationAction(back)
+
+ val forward = BrowserToolbar.Button(
+ resources.getThemedDrawable(iconsR.drawable.mozac_ic_forward_24)!!,
+ "Forward",
+ ) {
+ simulateReload()
+ }
+
+ binding.toolbar.addNavigationAction(forward)
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Add a "reload" browser action that simulates reloading the current page
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val reload = BrowserToolbar.TwoStateButton(
+ primaryImage = resources.getThemedDrawable(iconsR.drawable.mozac_ic_arrow_clockwise_24)!!,
+ primaryContentDescription = "Reload",
+ secondaryImage = resources.getThemedDrawable(iconsR.drawable.mozac_ic_stop)!!,
+ secondaryContentDescription = "Stop",
+ isInPrimaryState = { loading.value != true },
+ disableInSecondaryState = false,
+ ) {
+ if (loading.value == true) {
+ job?.cancel()
+ } else {
+ simulateReload()
+ }
+ }
+ binding.toolbar.addBrowserAction(reload)
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Create a menu that looks like the one in Firefox Focus
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val fenix = SimpleBrowserMenuItem("POWERED BY MOZILLA")
+ val share = SimpleBrowserMenuItem("Share…") { /* Do nothing */ }
+ val homeScreen = SimpleBrowserMenuItem("Add to Home screen") { /* Do nothing */ }
+ val open = SimpleBrowserMenuItem("Open in…") { /* Do nothing */ }
+ val settings = SimpleBrowserMenuItem("Settings") { /* Do nothing */ }
+
+ val items = listOf(fenix, share, homeScreen, open, settings)
+ binding.toolbar.display.menuBuilder = BrowserMenuBuilder(items)
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Display a URL
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ binding.toolbar.url = "https://www.mozilla.org/en-US/firefox/mobile/"
+ }
+
+ /**
+ * A custom browser menu.
+ */
+ private fun setupCustomMenu() {
+ binding.toolbar.setBackgroundColor(
+ ContextCompat.getColor(this, colorsR.color.photonBlue80),
+ )
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Create a menu with text and icons
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val share = TextMenuCandidate(
+ "Share",
+ start = DrawableMenuIcon(this, iconsR.drawable.mozac_ic_share_android_24),
+ ) { /* Do nothing */ }
+
+ val search = TextMenuCandidate(
+ "Search",
+ start = DrawableMenuIcon(this, iconsR.drawable.mozac_ic_search_24),
+ ) { /* Do nothing */ }
+
+ binding.toolbar.display.menuController = BrowserMenuController(Side.START).apply {
+ submitList(listOf(share, DividerMenuCandidate(), search))
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Display a URL
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ binding.toolbar.url = "https://www.mozilla.org/"
+ }
+
+ /**
+ * A toolbar that looks like Firefox Focus on phones.
+ */
+ private fun setupFocusPhoneToolbar() {
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Use the iconic gradient background
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val background = ContextCompat.getDrawable(this, R.drawable.focus_background)
+ binding.toolbar.background = background
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Create a "mini" toolbar to be shown inside the menu (forward, reload)
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val forward = BrowserMenuItemToolbar.Button(
+ iconsR.drawable.mozac_ic_forward_24,
+ "Forward",
+ isEnabled = { canGoForward() },
+ ) {
+ simulateReload()
+ }
+
+ val reload = BrowserMenuItemToolbar.TwoStateButton(
+ primaryImageResource = iconsR.drawable.mozac_ic_arrow_clockwise_24,
+ primaryContentDescription = "Reload",
+ secondaryImageResource = iconsR.drawable.mozac_ic_stop,
+ secondaryContentDescription = "Stop",
+ isInPrimaryState = { loading.value != true },
+ disableInSecondaryState = false,
+ ) {
+ if (loading.value == true) {
+ job?.cancel()
+ } else {
+ simulateReload()
+ }
+ }
+ // Redraw the reload button when loading state changes
+ loading.observe(this, Observer { binding.toolbar.invalidateActions() })
+
+ val menuToolbar = BrowserMenuItemToolbar(listOf(forward, reload))
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Create a custom "menu item" implementation that resembles Focus' global content blocking switch.
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val blocking = object : BrowserMenuItem {
+ // Always display this item. This lambda is executed when the user clicks on the menu
+ // button to determine whether this item should be shown.
+ override val visible = { true }
+
+ override fun getLayoutResource() = R.layout.focus_blocking_switch
+
+ override fun bind(menu: BrowserMenu, view: View) {
+ // Nothing to do here.
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Create a menu that looks like the one in Firefox Focus
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ val share = SimpleBrowserMenuItem("Share…") { /* Do nothing */ }
+ val homeScreen = SimpleBrowserMenuItem("Add to Home screen") { /* Do nothing */ }
+ val open = SimpleBrowserMenuItem("Open in…") { /* Do nothing */ }
+ val settings = SimpleBrowserMenuItem("Settings") { /* Do nothing */ }
+
+ val items = listOf(menuToolbar, blocking, share, homeScreen, open, settings)
+ binding.toolbar.display.menuBuilder = BrowserMenuBuilder(items)
+ binding.toolbar.invalidateActions()
+
+ // //////////////////////////////////////////////////////////////////////////////////////////
+ // Display a URL
+ // //////////////////////////////////////////////////////////////////////////////////////////
+
+ binding.toolbar.url = "https://www.mozilla.org/en-US/firefox/mobile/"
+ }
+
+ private class FakeTabCounterToolbarButton : Toolbar.Action {
+ override fun createView(parent: ViewGroup): View = TabCounter(parent.context).apply {
+ setCount(2)
+ setBackgroundResource(
+ parent.context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless),
+ )
+ }
+
+ override fun bind(view: View) = Unit
+ }
+
+ /**
+ * A toolbar that looks like the toolbar in Fenix (Light theme).
+ */
+ @Suppress("MagicNumber")
+ fun setupFenixToolbar() {
+ binding.toolbar.setBackgroundColor(0xFFFFFFFF.toInt())
+
+ binding.toolbar.display.indicators = listOf(
+ DisplayToolbar.Indicators.SECURITY,
+ DisplayToolbar.Indicators.TRACKING_PROTECTION,
+ DisplayToolbar.Indicators.EMPTY,
+ )
+
+ binding.toolbar.display.colors = binding.toolbar.display.colors.copy(
+ securityIconInsecure = 0xFF20123a.toInt(),
+ securityIconSecure = 0xFF20123a.toInt(),
+ text = 0xFF0c0c0d.toInt(),
+ menu = 0xFF20123a.toInt(),
+ separator = 0x1E15141a.toInt(),
+ trackingProtection = 0xFF20123a.toInt(),
+ emptyIcon = 0xFF20123a.toInt(),
+ hint = 0x1E15141a.toInt(),
+ )
+
+ binding.toolbar.display.urlFormatter = { url ->
+ URLStringUtils.toDisplayUrl(url)
+ }
+
+ binding.toolbar.display.setUrlBackground(
+ ContextCompat.getDrawable(this, R.drawable.fenix_url_background),
+ )
+ binding.toolbar.display.hint = "Search or enter address"
+ binding.toolbar.display.setOnUrlLongClickListener {
+ Toast.makeText(this, "Long click!", Toast.LENGTH_SHORT).show()
+ true
+ }
+
+ val share = TextMenuCandidate("Share…") { /* Do nothing */ }
+ val homeScreen = TextMenuCandidate("Add to Home screen") { /* Do nothing */ }
+ val open = TextMenuCandidate("Open in…") { /* Do nothing */ }
+ val settings = NestedMenuCandidate(
+ id = toolbarR.id.mozac_browser_toolbar_menu,
+ text = "Settings",
+ subMenuItems = listOf(
+ NestedMenuCandidate(id = menuR.id.container, text = "Back", subMenuItems = null),
+ TextMenuCandidate("Setting 1") { /* Do nothing */ },
+ TextMenuCandidate("Setting 2") { /* Do nothing */ },
+ ),
+ )
+
+ val items = listOf(share, homeScreen, open, settings)
+ binding.toolbar.display.menuController = BrowserMenuController().apply {
+ submitList(items)
+ }
+
+ binding.toolbar.url = "https://www.mozilla.org/en-US/firefox/mobile/"
+
+ binding.toolbar.addBrowserAction(FakeTabCounterToolbarButton())
+
+ binding.toolbar.display.setOnSiteSecurityClickedListener {
+ Toast.makeText(this, "Site security", Toast.LENGTH_SHORT).show()
+ }
+
+ binding.toolbar.edit.colors = binding.toolbar.edit.colors.copy(
+ text = 0xFF0c0c0d.toInt(),
+ clear = 0xFF0c0c0d.toInt(),
+ icon = 0xFF0c0c0d.toInt(),
+ )
+
+ binding.toolbar.edit.setUrlBackground(
+ ContextCompat.getDrawable(this, R.drawable.fenix_url_background),
+ )
+ binding.toolbar.edit.setIcon(
+ ContextCompat.getDrawable(this, iconsR.drawable.mozac_ic_search_24)!!,
+ "Search",
+ )
+
+ binding.toolbar.setOnUrlCommitListener { url ->
+ simulateReload()
+ binding.toolbar.url = url
+
+ true
+ }
+ }
+
+ /**
+ * A toolbar that looks like the toolbar in Fenix in a custom tab.
+ */
+ @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage
+ @Suppress("MagicNumber")
+ fun setupFenixCustomTabToolbar() {
+ binding.toolbar.setBackgroundColor(0xFFFFFFFF.toInt())
+
+ binding.toolbar.display.indicators = listOf(
+ DisplayToolbar.Indicators.SECURITY,
+ DisplayToolbar.Indicators.TRACKING_PROTECTION,
+ )
+
+ binding.toolbar.display.colors = binding.toolbar.display.colors.copy(
+ securityIconSecure = 0xFF20123a.toInt(),
+ securityIconInsecure = 0xFF20123a.toInt(),
+ text = 0xFF0c0c0d.toInt(),
+ title = 0xFF0c0c0d.toInt(),
+ menu = 0xFF20123a.toInt(),
+ separator = 0x1E15141a.toInt(),
+ trackingProtection = 0xFF20123a.toInt(),
+ )
+
+ val share = SimpleBrowserMenuItem("Share…") { /* Do nothing */ }
+ val homeScreen = SimpleBrowserMenuItem("Add to Home screen") { /* Do nothing */ }
+ val open = SimpleBrowserMenuItem("Open in…") { /* Do nothing */ }
+ val settings = SimpleBrowserMenuItem("Settings") { /* Do nothing */ }
+
+ val items = listOf(share, homeScreen, open, settings)
+ binding.toolbar.display.menuBuilder = BrowserMenuBuilder(items)
+ binding.toolbar.display.menuController = BrowserMenuController().apply {
+ submitList(items.asCandidateList(this@ToolbarActivity))
+ }
+
+ binding.toolbar.url = "https://www.mozilla.org/en-US/firefox/mobile/"
+
+ val drawableIcon = ContextCompat.getDrawable(this, iconsR.drawable.mozac_ic_cross_24)
+
+ drawableIcon?.apply {
+ setTint(0xFF20123a.toInt())
+ }.also {
+ val button = Toolbar.ActionButton(
+ it,
+ "Close",
+ ) {
+ Toast.makeText(this, "Close!", Toast.LENGTH_SHORT).show()
+ }
+ binding.toolbar.addNavigationAction(button)
+ }
+
+ val drawable = ContextCompat.getDrawable(this, iconsR.drawable.mozac_ic_share_android_24)?.apply {
+ setTint(0xFF20123a.toInt())
+ }
+
+ val button = Toolbar.ActionButton(drawable, "Share") {
+ Toast.makeText(this, "Share!", Toast.LENGTH_SHORT).show()
+ }
+
+ binding.toolbar.addBrowserAction(button)
+
+ binding.toolbar.display.setOnSiteSecurityClickedListener {
+ Toast.makeText(this, "Site security", Toast.LENGTH_SHORT).show()
+ }
+
+ GlobalScope.launch(Dispatchers.Main) {
+ delay(2000)
+ binding.toolbar.title = "Mobile browsers for iOS and Android | Firefox"
+ }
+ }
+
+ // For testing purposes
+ private var forward = true
+ private var back = true
+
+ private fun canGoForward(): Boolean = forward
+
+ @Suppress("UnusedPrivateMember")
+ private fun canGoBack(): Boolean = back
+
+ @Suppress("UnusedPrivateMember")
+ private fun goBack() {
+ back = !(forward && back)
+ forward = true
+ }
+
+ @Suppress("UnusedPrivateMember")
+ private fun goForward() {
+ forward = !(back && forward)
+ back = true
+ }
+
+ private var job: Job? = null
+
+ private var loading = MutableLiveData<Boolean>()
+
+ @Suppress("TooGenericExceptionCaught", "LongMethod", "ComplexMethod")
+ private fun simulateReload(view: UrlBoxProgressView? = null) {
+ job?.cancel()
+
+ loading.value = true
+
+ job = CoroutineScope(Dispatchers.Main).launch {
+ try {
+ loop@ for (progress in PROGRESS_RANGE step RELOAD_STEP_SIZE) {
+ if (!isActive) {
+ break@loop
+ }
+
+ if (view == null) {
+ binding.toolbar.displayProgress(progress)
+ } else {
+ view.progress = progress
+ }
+
+ delay(progress * RELOAD_STEP_SIZE.toLong())
+ }
+ } catch (t: Throwable) {
+ if (view == null) {
+ binding.toolbar.displayProgress(0)
+ } else {
+ view.progress = 0
+ }
+
+ throw t
+ } finally {
+ loading.value = false
+
+ // Update toolbar buttons to reflect loading state
+ binding.toolbar.invalidateActions()
+ }
+ }
+
+ // Update toolbar buttons to reflect loading state
+ binding.toolbar.invalidateActions()
+ }
+
+ private fun Resources.getThemedDrawable(@DrawableRes resId: Int) = ResourcesCompat.getDrawable(this, resId, theme)
+
+ companion object {
+ private val PROGRESS_RANGE = 0..100
+ private const val RELOAD_STEP_SIZE = 5
+ }
+}
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/drawable/fenix_url_background.xml b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/fenix_url_background.xml
new file mode 100644
index 0000000000..3db3318893
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/fenix_url_background.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#E6E8E8" />
+
+ <corners
+ android:bottomLeftRadius="8dp"
+ android:bottomRightRadius="8dp"
+ android:topLeftRadius="8dp"
+ android:topRightRadius="8dp" />
+</shape> \ No newline at end of file
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/drawable/focus_background.xml b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/focus_background.xml
new file mode 100644
index 0000000000..c2f0193bb4
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/focus_background.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:angle="315"
+ android:startColor="#ffa01142"
+ android:centerColor="#ff90116D"
+ android:endColor="#ff5c1166" />
+</shape> \ No newline at end of file
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_background.xml b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_background.xml
new file mode 100644
index 0000000000..5537e32d4d
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#FF2A2A2E" />
+ <corners android:radius="4dp" />
+</shape>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_progress.xml b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_progress.xml
new file mode 100644
index 0000000000..a1404243be
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/drawable/sample_url_progress.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#ff45a1ff" />
+ <corners android:radius="4dp" />
+</shape>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/layout/activity_toolbar.xml b/mobile/android/android-components/samples/toolbar/src/main/res/layout/activity_toolbar.xml
new file mode 100644
index 0000000000..48bda7881c
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/layout/activity_toolbar.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".ToolbarActivity">
+
+ <mozilla.components.browser.toolbar.BrowserToolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+</LinearLayout>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/layout/focus_blocking_switch.xml b/mobile/android/android-components/samples/toolbar/src/main/res/layout/focus_blocking_switch.xml
new file mode 100644
index 0000000000..6245c6ce46
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/layout/focus_blocking_switch.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="80dp"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:background="#272727"
+ tools:ignore="Overdraw"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingEnd="0dp"
+ android:paddingStart="16dp">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="2dp"
+ android:ellipsize="end"
+ android:text="@string/trackers_blocked"
+ android:textColor="#80FFFFFF"
+ android:textSize="16sp" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+
+ <TextView
+ android:id="@+id/trackers_count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="#ffffff"
+ android:textSize="24sp"
+ tools:text="42" />
+
+ <ImageButton
+ android:id="@+id/help_trackers"
+ android:contentDescription="@string/help_trackers_description"
+ android:layout_width="22dp"
+ android:layout_height="22dp"
+ android:padding="4dp"
+ app:srcCompat="@drawable/mozac_ic_information_fill_24"
+ android:background="?android:attr/selectableItemBackgroundBorderless" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <androidx.appcompat.widget.SwitchCompat
+ android:id="@+id/blocking_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical|end"
+ android:background="?android:attr/selectableItemBackground"
+ android:checked="true"
+ android:clickable="true"
+ android:focusable="true"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:lines="1"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:textSize="16sp"/>
+
+</LinearLayout>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/layout/item_toolbar_configuration.xml b/mobile/android/android-components/samples/toolbar/src/main/res/layout/item_toolbar_configuration.xml
new file mode 100644
index 0000000000..d7c2560465
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/layout/item_toolbar_configuration.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ tools:ignore="Overdraw"
+ android:clickable="true"
+ android:focusable="true"
+ android:textSize="14sp"
+ android:padding="16dp" />
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000000..ff5b811c28
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background"/>
+ <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+</adaptive-icon> \ No newline at end of file
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000000..ff5b811c28
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background"/>
+ <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+</adaptive-icon> \ No newline at end of file
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..f53686af1d
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..361ce175fe
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_round.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..eeb463471b
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..9466bb3aee
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..c158a5aa08
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_round.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..4658edf3ae
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..21410ec0f8
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..2233cd4525
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..9f62938988
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..8b0c76270e
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..ea69f75cd7
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..1414185bd2
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..41288de783
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..beccb228ea
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..5ab06ff36d
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/values/colors.xml b/mobile/android/android-components/samples/toolbar/src/main/res/values/colors.xml
new file mode 100644
index 0000000000..abbf1bdbcc
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/values/colors.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<resources>
+ <color name="selected_configuration">#222222</color>
+</resources>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/values/dimens.xml b/mobile/android/android-components/samples/toolbar/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000..dff0755716
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/values/dimens.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <dimen tools:ignore="UnusedResources" name="mozac_browser_menu_corner_radius">20dp</dimen>
+ <dimen tools:ignore="UnusedResources" name="mozac_browser_menu2_corner_radius">20dp</dimen>
+</resources>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/values/ic_launcher_background.xml b/mobile/android/android-components/samples/toolbar/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000000..475311a475
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<resources>
+ <color name="ic_launcher_background">#FF618D</color>
+</resources> \ No newline at end of file
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/values/strings.xml b/mobile/android/android-components/samples/toolbar/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..81a1535a0e
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/values/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<resources>
+ <string name="app_name">Toolbar Sample</string>
+ <string name="trackers_blocked">Trackers blocked</string>
+ <string name="help_trackers_description">About Trackers</string>
+</resources>
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/xml/backup_rules.xml b/mobile/android/android-components/samples/toolbar/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000000..820ae61afa
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<full-backup-content>
+ <include domain="sharedpref" path="."/>
+</full-backup-content> \ No newline at end of file
diff --git a/mobile/android/android-components/samples/toolbar/src/main/res/xml/data_extraction_rules.xml b/mobile/android/android-components/samples/toolbar/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000000..55da967560
--- /dev/null
+++ b/mobile/android/android-components/samples/toolbar/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<data-extraction-rules>
+ <cloud-backup>
+ <include domain="sharedpref" path="."/>
+ </cloud-backup>
+</data-extraction-rules> \ No newline at end of file