Files
Claudio DeSouza cffb249298 [cr149] FindLastActiveWithProfile returning BWI
This change allows a couple of more places to be migrated to
`BrowserWindowInterface`.

Chromium changes:
https://chromium.googlesource.com/chromium/src/+/e8d0df41d25900497716dd3a4b070c6436fa1a97

commit e8d0df41d25900497716dd3a4b070c6436fa1a97
Author: Kun Wang <kunwang@microsoft.com>
Date:   Wed Apr 15 23:35:39 2026 -0700

    [bedrock] Migrate FindLastActiveWithProfile Step 1

    Bug: 494010890
    Change-Id: Ie0385deeda2e2f28baf75a810ada0becf5807c78
    Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7753884
    Reviewed-by: Thomas Lukaszewicz <tluk@chromium.org>
    Reviewed-by: Qikai Zhong <qikaizhong@microsoft.com>
    Commit-Queue: Kun Wang <kunwang@microsoft.com>
    Cr-Commit-Position: refs/heads/main@{#1615659}
2026-05-22 16:24:59 -04:00

316 lines
9.8 KiB
C++

// Copyright (c) 2023 The Brave Authors. All rights reserved.
// 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 https://mozilla.org/MPL/2.0/.
#include "brave/browser/ui/commander/commander_service.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/task/sequenced_task_runner.h"
#include "brave/browser/ui/commander/bookmark_command_source.h"
#include "brave/browser/ui/commander/command_source.h"
#include "brave/browser/ui/commander/ranker.h"
#include "brave/browser/ui/commander/simple_command_source.h"
#include "brave/browser/ui/commander/tab_command_source.h"
#include "brave/browser/ui/commander/window_command_source.h"
#include "brave/components/commander/browser/commander_frontend_delegate.h"
#include "brave/components/commander/browser/commander_item_model.h"
#include "brave/components/commander/common/constants.h"
#include "brave/components/commander/common/features.h"
#include "brave/components/omnibox/browser/brave_omnibox_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/browser_window/public/global_browser_collection.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
namespace commander {
namespace {
constexpr size_t kMaxResults = 8;
CommandItemModel FromCommand(const std::unique_ptr<CommandItem>& item) {
return CommandItemModel(item->title, item->matched_ranges, item->annotation,
item->score);
}
} // namespace
bool IsEnabled() {
return base::FeatureList::IsEnabled(features::kBraveCommander);
}
CommanderService::CommanderService(Profile* profile)
: profile_(profile), ranker_(profile->GetPrefs()) {
command_sources_.push_back(std::make_unique<SimpleCommandSource>());
command_sources_.push_back(std::make_unique<BookmarkCommandSource>());
command_sources_.push_back(std::make_unique<WindowCommandSource>());
command_sources_.push_back(std::make_unique<TabCommandSource>());
}
CommanderService::~CommanderService() = default;
void CommanderService::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
observer->OnCommanderUpdated();
}
void CommanderService::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void CommanderService::UpdateText(const std::u16string& text) {
UpdateText(text, false);
}
void CommanderService::SelectCommand(uint32_t command_index,
uint32_t result_set_id) {
if (command_index >= items_.size() ||
result_set_id != current_result_set_id_) {
return;
}
// Increment the current result set id - we don't want any commands from this
// set to be reused after we've selected a command.
// Note: This needs to happen before beginning a composite command, to ensure
// that the generated model uses right right |result_set_id|.
current_result_set_id_++;
auto* item = items_[command_index].get();
// Record that we selected this command to increase it's rank next time.
ranker_.Visit(*item);
if (item->GetType() == CommandItem::Type::kOneShot) {
std::move(std::get<base::OnceClosure>(item->command)).Run();
Hide();
} else {
auto composite_command =
std::get<CommandItem::CompositeCommand>(item->command);
std::tie(prompt_, composite_command_provider_) = composite_command;
Show();
}
}
std::vector<CommandItemModel> CommanderService::GetItems() {
std::vector<CommandItemModel> result;
std::ranges::transform(items_, std::back_inserter(result), FromCommand);
return result;
}
int CommanderService::GetResultSetId() {
return current_result_set_id_;
}
const std::u16string& CommanderService::GetPrompt() {
return prompt_;
}
void CommanderService::Shutdown() {
weak_ptr_factory_.InvalidateWeakPtrs();
items_.clear();
}
void CommanderService::EnsureBrowserDidCloseSubscription(
BrowserWindowInterface* browser_window_interface) {
if (browser_close_subscriptions_.contains(browser_window_interface)) {
return;
}
browser_close_subscriptions_[browser_window_interface] =
browser_window_interface->RegisterBrowserDidClose(
base::BindRepeating(&CommanderService::OnBrowserDidClose,
weak_ptr_factory_.GetWeakPtr()));
}
void CommanderService::OnBrowserCreated(BrowserWindowInterface* browser) {
EnsureBrowserDidCloseSubscription(browser);
}
void CommanderService::OnBrowserDidClose(BrowserWindowInterface* browser) {
browser_close_subscriptions_.erase(browser);
if (last_browser_ == browser) {
last_browser_ = nullptr;
browser_collection_observation_.Reset();
}
}
void CommanderService::Toggle() {
if (IsShowing()) {
Hide();
} else {
Show();
}
}
void CommanderService::Show() {
// Note: This posts a task because we can't change the Omnibox text while
// autocompleting.
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&CommanderService::ShowCommander,
weak_ptr_factory_.GetWeakPtr()));
}
void CommanderService::Hide() {
// Note: This posts a task because we can't change the Omnibox text while
// autocompleting.
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&CommanderService::HideCommander,
weak_ptr_factory_.GetWeakPtr()));
}
void CommanderService::Reset() {
current_result_set_id_++;
items_.clear();
prompt_.clear();
last_searched_.clear();
last_browser_ = nullptr;
if (composite_command_provider_) {
composite_command_provider_.Reset();
}
NotifyObservers();
}
void CommanderService::UpdateTextFromCurrentBrowserOmnibox() {
auto* browser = chrome::FindLastActiveWithProfile(profile_);
// The last active browser can have no tabs, if we're in the process of moving
// the last tab from the current window into another one.
if (!browser || browser->GetTabStripModel()->empty()) {
return;
}
auto text =
browser->GetFeatures().location_bar()->GetOmniboxView()->GetText();
UpdateText(text, /*force=*/true);
}
void CommanderService::UpdateText(const std::u16string& text, bool force) {
auto* browser = chrome::FindLastActiveWithProfile(profile_);
if (!browser) {
return;
}
auto has_prefix = text.starts_with(kCommandPrefix);
if (!has_prefix && !browser->GetProfile()->GetPrefs()->GetBoolean(
omnibox::kCommanderSuggestionsEnabled)) {
return;
}
if (text.empty()) {
return;
}
std::u16string trimmed_text(
has_prefix ? base::TrimWhitespace(text.substr(kCommandPrefix.size()),
base::TRIM_LEADING)
: text);
// If nothing has changed (and we aren't forcing things), don't update the
// commands.
if (trimmed_text == last_searched_ && browser == last_browser_ && !force) {
return;
}
last_searched_ = trimmed_text;
last_browser_ = browser;
EnsureBrowserDidCloseSubscription(browser);
if (!browser_collection_observation_.IsObserving()) {
browser_collection_observation_.Observe(
GlobalBrowserCollection::GetInstance());
}
UpdateCommands();
}
OmniboxView* CommanderService::GetOmnibox() const {
auto* browser = chrome::FindLastActiveWithProfile(profile_);
if (!browser) {
return nullptr;
}
return browser->GetFeatures().location_bar()->GetOmniboxView();
}
bool CommanderService::IsShowing() const {
auto* omnibox = GetOmnibox();
return omnibox && omnibox->GetText().starts_with(kCommandPrefix.data());
}
void CommanderService::UpdateCommands() {
std::vector<std::unique_ptr<CommandItem>> items;
if (composite_command_provider_) {
items = composite_command_provider_.Run(last_searched_);
} else {
for (auto& source : command_sources_) {
auto commands = source->GetCommands(last_searched_, last_browser_);
items.insert(items.end(), std::make_move_iterator(commands.begin()),
std::make_move_iterator(commands.end()));
}
}
ranker_.Rank(items, kMaxResults);
if (items.size() > kMaxResults) {
items.resize(kMaxResults);
}
items_ = std::move(items);
// Increment the current result set id, so we don't confuse these results with
// a prior set before notifying observers.
current_result_set_id_++;
NotifyObservers();
}
void CommanderService::NotifyObservers() {
for (auto& observer : observers_) {
observer.OnCommanderUpdated();
}
}
void CommanderService::ShowCommander() {
if (auto* omnibox = GetOmnibox()) {
omnibox->SetFocus(true);
auto text = base::StrCat({commander::kCommandPrefix, u" "});
omnibox->SetUserText(text);
omnibox->SetCaretPos(text.size());
UpdateTextFromCurrentBrowserOmnibox();
}
}
void CommanderService::HideCommander() {
// Snapshot whether we need to revert before Reset(): observers notified by
// Reset() can touch autocomplete state such that IsShowing() no longer
// reflects commander visibility reliably during shutdown steps.
bool had_commander_omnibox_prefix = false;
if (OmniboxView* omnibox = GetOmnibox()) {
had_commander_omnibox_prefix =
omnibox->GetText().starts_with(kCommandPrefix.data());
}
Reset();
if (had_commander_omnibox_prefix) {
if (OmniboxView* omnibox = GetOmnibox()) {
omnibox->RevertAll();
}
}
}
} // namespace commander