diff --git a/app/metrics.yaml b/app/metrics.yaml index b1b5e11730..c42765f635 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -54,14 +54,19 @@ events: description: > A user performed a search extra_keys: - search_suggestion: - description: "A boolean that tells us whether or not the search term was suggested by the Awesomebar" - search_shortcut: - description: "A boolean that tells us whether or not the search was conducted through a search shortcut" + source: + description: > + A string that tells us how the user performed the search. Possible values are: + * default.action + * default.suggestion + * shortcut.action + * shortcut.suggestion + bugs: - 959 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673 + - https://github.com/mozilla-mobile/fenix/pull/1677 notification_emails: - fenix-core@mozilla.com expires: "2020-03-01" @@ -307,6 +312,24 @@ metrics: notification_emails: - fenix-core@mozilla.com expires: "2020-03-01" + search_count: + type: labeled_counter + description: > + The labels for this counter are `.`. + + If the search engine is bundled with Fenix `search-engine-name` will be the name of the search engine. If it's a + custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be `custom`. + + `source` will either be `action` or `suggestion` + send_in_pings: + - metrics + bugs: + - 1158 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/1677 + notification_emails: + - fenix-core@mozilla.com + expires: "2019-09-01" search.default_engine: code: @@ -357,4 +380,4 @@ search.default_engine: - https://github.com/mozilla-mobile/fenix/issues/1607 notification_emails: - fenix-core@mozilla.com - expires: "2019-09-01" + expires: "2019-09-01" \ No newline at end of file diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt index 277d8587fa..e186bc87e5 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt @@ -52,7 +52,10 @@ private val Event.wrapper { Events.enteredUrlKeys.valueOf(it) } ) is Event.PerformedSearch -> EventWrapper( - { Events.performedSearch.record(it) }, + { + Metrics.searchCount[this.eventSource.countLabel].add(1) + Events.performedSearch.record(it) + }, { Events.performedSearchKeys.valueOf(it) } ) is Event.FindInPageOpened -> EventWrapper( diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt index 2d8e60a38a..e043ac15e1 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.fenix.components.metrics +import mozilla.components.browser.search.SearchEngine import mozilla.components.support.base.Component import mozilla.components.support.base.facts.Fact import mozilla.components.support.base.facts.FactProcessor @@ -69,10 +70,49 @@ sealed class Event { get() = mapOf("autocomplete" to autoCompleted.toString()) } - data class PerformedSearch(val fromSearchSuggestion: Boolean, val fromSearchShortcut: Boolean) : Event() { + data class PerformedSearch(val eventSource: EventSource) : Event() { + sealed class EngineSource { + data class Default(val engine: SearchEngine) : EngineSource() + data class Shortcut(val engine: SearchEngine) : EngineSource() + + val searchEngine: SearchEngine + get() = when (this) { + is Default -> engine + is Shortcut -> engine + } + + val descriptor: String + get() = when (this) { + is Default -> "default" + is Shortcut -> "shortcut" + } + } + + sealed class EventSource { + data class Suggestion(val engineSource: EngineSource) : EventSource() + data class Action(val engineSource: EngineSource) : EventSource() + + private val source: EngineSource + get() = when (this) { + is Suggestion -> engineSource + is Action -> engineSource + } + + private val label: String + get() = when (this) { + is Suggestion -> "suggestion" + is Action -> "action" + } + + val countLabel: String + get() = "${source.searchEngine.identifier}.$label" + + val sourceLabel: String + get() = "${source.descriptor}.$label" + } + override val extras: Map? - get() = mapOf("search_suggestion" to fromSearchSuggestion.toString(), - "search_shortcut" to fromSearchShortcut.toString()) + get() = mapOf("source" to eventSource.sourceLabel) } // Track only built-in engine selection. Do not track user-added engines! @@ -122,6 +162,8 @@ sealed class Event { get() = mapOf("item" to item.toString().toLowerCase()) } + sealed class Search + open val extras: Map? get() = null } 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 1b8ed08cf4..8c7510ad93 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt @@ -120,7 +120,9 @@ class SearchFragment : Fragment() { val event = if (it.url.isUrl()) { Event.EnteredUrl(false) } else { - Event.PerformedSearch(false, isSearchShortcut(it.engine)) + if (it.engine == null) { return@subscribe } + + createSearchEvent(it.engine, false) } requireComponents.analytics.metrics.track(event) @@ -150,8 +152,10 @@ class SearchFragment : Fragment() { .invoke(it.searchTerms, it.engine) (activity as HomeActivity).openToBrowser(sessionId, BrowserDirection.FromSearch) - requireComponents.analytics.metrics - .track(Event.PerformedSearch(true, isSearchShortcut(it.engine))) + if (it.engine == null) { return@subscribe } + val event = createSearchEvent(it.engine, true) + + requireComponents.analytics.metrics.track(event) } is AwesomeBarAction.SearchShortcutEngineSelected -> { getManagedEmitter() @@ -165,6 +169,20 @@ class SearchFragment : Fragment() { } } + private fun createSearchEvent(engine: SearchEngine, isSuggestion: Boolean): Event.PerformedSearch { + val isShortcut = engine != requireComponents.search.searchEngineManager.defaultSearchEngine + + val engineSource = + if (isShortcut) Event.PerformedSearch.EngineSource.Shortcut(engine) + else Event.PerformedSearch.EngineSource.Default(engine) + + val source = + if (isSuggestion) Event.PerformedSearch.EventSource.Suggestion(engineSource) + else Event.PerformedSearch.EventSource.Action(engineSource) + + return Event.PerformedSearch(source) + } + private fun getSearchUseCase(context: Context, useNewTab: Boolean): SearchUseCases.SearchUseCase { if (!useNewTab) { return context.components.useCases.searchUseCases.defaultSearch @@ -186,8 +204,4 @@ class SearchFragment : Fragment() { false -> context.components.useCases.tabsUseCases.addTab } } - - private fun isSearchShortcut(engine: SearchEngine?): Boolean { - return engine != null && engine != requireComponents.search.searchEngineManager.defaultSearchEngine - } }