blob: 8b79f856c617b863884a2372fa09328826c60d3a [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/omnibox/browser/history_cluster_provider.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/history_clusters/core/config.h"
#include "components/history_clusters/core/history_clusters_service.h"
#include "components/omnibox/browser/autocomplete_controller.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/autocomplete_match_classification.h"
#include "components/omnibox/browser/autocomplete_match_type.h"
#include "components/omnibox/browser/autocomplete_provider_client.h"
#include "components/omnibox/browser/autocomplete_provider_listener.h"
#include "components/omnibox/browser/search_provider.h"
#include "components/omnibox/browser/suggestion_group.h"
HistoryClusterProvider::HistoryClusterProvider(
AutocompleteProviderClient* client,
AutocompleteProviderListener* listener,
SearchProvider* search_provider)
: AutocompleteProvider(AutocompleteProvider::TYPE_HISTORY_CLUSTER_PROVIDER),
client_(client),
search_provider_(search_provider) {
DCHECK(search_provider_);
AddListener(listener);
search_provider_->AddListener(this);
}
void HistoryClusterProvider::Start(const AutocompleteInput& input,
bool minimal_changes) {
Stop(true, false);
if (input.omit_asynchronous_matches())
return;
if (!IsJourneysEnabledInOmnibox(client_->GetHistoryClustersService(),
client_->GetPrefs())) {
return;
}
if (!history_clusters::GetConfig().omnibox_history_cluster_provider)
return;
done_ = false;
input_ = input;
if (search_provider_->done())
CreateMatches();
}
void HistoryClusterProvider::OnProviderUpdate(
bool updated_matches,
const AutocompleteProvider* provider) {
if (done_ || !search_provider_->done())
return;
NotifyListeners(CreateMatches());
}
bool HistoryClusterProvider::CreateMatches() {
done_ = true;
// Iterate search matches in their current order. This is usually highest to
// lowest relevance with an exception for search-what-you-typed search
// suggestions being ordered before others.
for (const auto& search_match : search_provider_->matches()) {
if (client_->GetHistoryClustersService()->DoesQueryMatchAnyCluster(
base::UTF16ToUTF8(search_match.contents))) {
matches_.push_back(CreateMatch(search_match.contents));
return true;
}
}
return false;
}
AutocompleteMatch HistoryClusterProvider::CreateMatch(std::u16string text) {
AutocompleteMatch match;
match.provider = this;
match.type = AutocompleteMatch::Type::HISTORY_CLUSTER;
// 900 seems to work well in local tests. It's high enough to
// outscore search suggestions and therefore not be crowded out, but low
// enough to only display when there aren't too many strong navigation
// matches.
// TODO(manukh): Currently, history cluster suggestions only display when the
// `text` is an exact match of a cluster keyword, and all cluster keywords
// are treated equal. Therefore, we're limited to using a static value.
// Ideally, relevance would depend on how many keywords matched, how
// significant the keywords were, how significant their clusters were etc.
match.relevance = 900;
match.fill_into_edit = base::UTF8ToUTF16(base::StringPrintf(
"chrome://history/journeys?q=%s", base::UTF16ToUTF8(text).c_str()));
match.destination_url = GURL(base::UTF8ToUTF16(base::StringPrintf(
"chrome://history/journeys?q=%s",
base::EscapeQueryParamValue(base::UTF16ToUTF8(text), /*use_plus=*/false)
.c_str())));
match.description = text;
match.description_class = ClassifyTermMatches(
FindTermMatches(input_.text(), text), text.length(),
ACMatchClassification::MATCH, ACMatchClassification::NONE);
match.contents = match.fill_into_edit;
match.contents_class.push_back(
ACMatchClassification(0, ACMatchClassification::URL));
match.suggestion_group_id = SuggestionGroupId::kHistoryCluster;
// Insert a corresponding SuggestionGroup with default values in the
// suggestion groups map; otherwise the group ID will get dropped.
suggestion_groups_map_[SuggestionGroupId::kHistoryCluster];
return match;
}