blob: 1a1551c7312e811004e6bf2638ea27699c07bb5f [file] [log] [blame]
// Copyright 2012 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 "chrome/browser/ui/browser_commands.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/escape.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/apps/app_service/app_launch_params.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/browser_app_launcher.h"
#include "chrome/browser/apps/intent_helper/intent_picker_helpers.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/dom_distiller/tab_utils.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/favicon/favicon_utils.h"
#include "chrome/browser/feed/web_feed_ui_util.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_base.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/sessions/session_service_lookup.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/ui/accelerator_utils.h"
#include "chrome/browser/ui/autofill/payments/manage_migration_ui_controller.h"
#include "chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.h"
#include "chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h"
#include "chrome/browser/ui/bookmarks/bookmark_stats.h"
#include "chrome/browser/ui/bookmarks/bookmark_utils.h"
#include "chrome/browser/ui/bookmarks/bookmark_utils_desktop.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_command_controller.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_live_tab_context.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/commander/commander.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
#include "chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.h"
#include "chrome/browser/ui/read_later/reading_list_model_factory.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.h"
#include "chrome/browser/ui/sharing_hub/screenshot/screenshot_captured_bubble_controller.h"
#include "chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller.h"
#include "chrome/browser/ui/startup/startup_tab.h"
#include "chrome/browser/ui/status_bubble.h"
#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
#include "chrome/browser/ui/tab_dialogs.h"
#include "chrome/browser/ui/tabs/tab_group.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
#include "chrome/browser/ui/translate/translate_bubble_ui_action_logger.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/user_education/reopen_tab_in_product_help.h"
#include "chrome/browser/ui/user_education/reopen_tab_in_product_help_factory.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_id.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/content_restriction.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/bookmark_utils.h"
#include "components/bookmarks/common/bookmark_pref_names.h"
#include "components/browsing_data/content/browsing_data_helper.h"
#include "components/dom_distiller/core/url_utils.h"
#include "components/embedder_support/user_agent_utils.h"
#include "components/favicon/content/content_favicon_driver.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/find_in_page/find_tab_helper.h"
#include "components/find_in_page/find_types.h"
#include "components/google/core/common/google_util.h"
#include "components/media_router/browser/media_router_dialog_controller.h" // nogncheck
#include "components/media_router/browser/media_router_metrics.h"
#include "components/omnibox/browser/omnibox_prefs.h"
#include "components/prefs/pref_service.h"
#include "components/reading_list/core/reading_list_entry.h"
#include "components/reading_list/core/reading_list_model.h"
#include "components/reading_list/core/reading_list_pref_names.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "components/sessions/core/live_tab_context.h"
#include "components/sessions/core/tab_restore_service.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "components/translate/core/browser/language_state.h"
#include "components/user_education/common/feature_promo_controller.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "components/zoom/page_zoom.h"
#include "components/zoom/zoom_controller.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "content/public/common/user_agent.h"
#include "extensions/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "rlz/buildflags/buildflags.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/models/list_selection_model.h"
#include "ui/base/window_open_disposition.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "url/gurl.h"
#include "url/url_constants.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/ui/extensions/app_launch_params.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
#include "chrome/common/extensions/extension_metrics.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#endif
#if BUILDFLAG(ENABLE_PRINTING)
#include "chrome/browser/printing/print_view_manager_common.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
#include "chrome/browser/printing/print_preview_dialog_controller.h"
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
#endif // BUILDFLAG(ENABLE_PRINTING)
#if BUILDFLAG(ENABLE_RLZ)
#include "components/rlz/rlz_tracker.h" // nogncheck
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/crosapi/mojom/task_manager.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#endif
namespace {
const char kOsOverrideForTabletSite[] = "Linux; Android 9; Chrome tablet";
const char kChPlatformOverrideForTabletSite[] = "Android";
translate::TranslateBubbleUiEvent TranslateBubbleResultToUiEvent(
ShowTranslateBubbleResult result) {
switch (result) {
default:
NOTREACHED();
[[fallthrough]];
case ShowTranslateBubbleResult::SUCCESS:
return translate::TranslateBubbleUiEvent::BUBBLE_SHOWN;
case ShowTranslateBubbleResult::BROWSER_WINDOW_MINIMIZED:
return translate::TranslateBubbleUiEvent::
BUBBLE_NOT_SHOWN_WINDOW_MINIMIZED;
case ShowTranslateBubbleResult::EDITABLE_FIELD_IS_ACTIVE:
return translate::TranslateBubbleUiEvent::
BUBBLE_NOT_SHOWN_EDITABLE_FIELD_IS_ACTIVE;
}
}
// Creates a new tabbed browser window, with the same size, type and profile as
// |original_browser|'s window, inserts |contents| into it, and shows it.
void CreateAndShowNewWindowWithContents(
std::unique_ptr<content::WebContents> contents,
const Browser* original_browser) {
Browser* new_browser = nullptr;
DCHECK(!original_browser->is_type_app_popup());
if (original_browser->is_type_app()) {
new_browser = Browser::Create(Browser::CreateParams::CreateForApp(
original_browser->app_name(), original_browser->is_trusted_source(),
gfx::Rect(), original_browser->profile(), true));
} else {
new_browser = Browser::Create(Browser::CreateParams(
original_browser->type(), original_browser->profile(), true));
}
// Preserve the size of the original window. The new window has already
// been given an offset by the OS, so we shouldn't copy the old bounds.
BrowserWindow* new_window = new_browser->window();
new_window->SetBounds(
gfx::Rect(new_window->GetRestoredBounds().origin(),
original_browser->window()->GetRestoredBounds().size()));
// We need to show the browser now. Otherwise ContainerWin assumes the
// WebContents is invisible and won't size it.
new_browser->window()->Show();
// The page transition below is only for the purpose of inserting the tab.
new_browser->tab_strip_model()->AddWebContents(std::move(contents), -1,
ui::PAGE_TRANSITION_LINK,
TabStripModel::ADD_ACTIVE);
}
bool GetTabURLAndTitleToSave(content::WebContents* web_contents,
GURL* url,
std::u16string* title) {
// |web_contents| can be nullptr if the last tab in the browser was closed
// but the browser wasn't closed yet. https://crbug.com/799668
if (!web_contents)
return false;
return chrome::GetURLAndTitleToBookmark(web_contents, url, title);
}
ReadingListModel* GetReadingListModel(Browser* browser) {
ReadingListModel* model =
ReadingListModelFactory::GetForBrowserContext(browser->profile());
if (!model || !model->loaded())
return nullptr; // Ignore requests until model has loaded.
return model;
}
bool CanMoveWebContentsToReadLater(Browser* browser,
content::WebContents* web_contents,
ReadingListModel* model,
GURL* url,
std::u16string* title) {
return model && GetTabURLAndTitleToSave(web_contents, url, title) &&
model->IsUrlSupported(*url) && !browser->profile()->IsGuestSession();
}
} // namespace
using base::UserMetricsAction;
using bookmarks::BookmarkModel;
using content::NavigationController;
using content::NavigationEntry;
using content::OpenURLParams;
using content::Referrer;
using content::WebContents;
namespace chrome {
namespace {
#if BUILDFLAG(ENABLE_EXTENSIONS)
const extensions::Extension* GetExtensionForBrowser(Browser* browser) {
return extensions::ExtensionRegistry::Get(browser->profile())
->GetExtensionById(
web_app::GetAppIdFromApplicationName(browser->app_name()),
extensions::ExtensionRegistry::EVERYTHING);
}
#endif
// Based on |disposition|, creates a new tab as necessary, and returns the
// appropriate tab to navigate. If that tab is the |current_tab|, reverts the
// location bar contents, since all browser-UI-triggered navigations should
// revert any omnibox edits in the |current_tab|.
WebContents* GetTabAndRevertIfNecessaryHelper(Browser* browser,
WindowOpenDisposition disposition,
WebContents* current_tab) {
switch (disposition) {
case WindowOpenDisposition::NEW_FOREGROUND_TAB:
case WindowOpenDisposition::NEW_BACKGROUND_TAB: {
std::unique_ptr<WebContents> new_tab = current_tab->Clone();
WebContents* raw_new_tab = new_tab.get();
if (disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB)
new_tab->WasHidden();
const int index =
browser->tab_strip_model()->GetIndexOfWebContents(current_tab);
const auto group = browser->tab_strip_model()->GetTabGroupForTab(index);
browser->tab_strip_model()->AddWebContents(
std::move(new_tab), -1, ui::PAGE_TRANSITION_LINK,
(disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB)
? TabStripModel::ADD_ACTIVE
: TabStripModel::ADD_NONE,
group);
return raw_new_tab;
}
case WindowOpenDisposition::NEW_WINDOW: {
std::unique_ptr<WebContents> new_tab = current_tab->Clone();
WebContents* raw_new_tab = new_tab.get();
Browser* new_browser =
Browser::Create(Browser::CreateParams(browser->profile(), true));
new_browser->tab_strip_model()->AddWebContents(std::move(new_tab), -1,
ui::PAGE_TRANSITION_LINK,
TabStripModel::ADD_ACTIVE);
new_browser->window()->Show();
return raw_new_tab;
}
default:
browser->window()->GetLocationBar()->Revert();
return current_tab;
}
}
// Like the above, but auto-computes the current tab
WebContents* GetTabAndRevertIfNecessary(Browser* browser,
WindowOpenDisposition disposition) {
WebContents* activate_tab =
browser->tab_strip_model()->GetActiveWebContents();
return GetTabAndRevertIfNecessaryHelper(browser, disposition, activate_tab);
}
void ReloadInternal(Browser* browser,
WindowOpenDisposition disposition,
bool bypass_cache) {
const WebContents* active_contents =
browser->tab_strip_model()->GetActiveWebContents();
const auto& selected_indices =
browser->tab_strip_model()->selection_model().selected_indices();
for (int index : selected_indices) {
WebContents* selected_tab =
browser->tab_strip_model()->GetWebContentsAt(index);
WebContents* new_tab =
GetTabAndRevertIfNecessaryHelper(browser, disposition, selected_tab);
// If the selected_tab is the activated page, give the focus to it, as this
// is caused by a user action
if (selected_tab == active_contents &&
!new_tab->FocusLocationBarByDefault()) {
new_tab->Focus();
}
DevToolsWindow* devtools =
DevToolsWindow::GetInstanceForInspectedWebContents(new_tab);
constexpr content::ReloadType kBypassingType =
content::ReloadType::BYPASSING_CACHE;
constexpr content::ReloadType kNormalType = content::ReloadType::NORMAL;
if (!devtools || !devtools->ReloadInspectedWebContents(bypass_cache)) {
new_tab->GetController().Reload(
bypass_cache ? kBypassingType : kNormalType, true);
}
}
}
bool IsShowingWebContentsModalDialog(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
if (!web_contents)
return false;
// TODO(gbillock): This is currently called in production by the CanPrint
// method, and may be too restrictive if we allow print preview to overlap.
// Re-assess how to queue print preview after we know more about popup
// management policy.
const web_modal::WebContentsModalDialogManager* manager =
web_modal::WebContentsModalDialogManager::FromWebContents(web_contents);
return manager && manager->IsDialogActive();
}
#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
bool PrintPreviewShowing(const Browser* browser) {
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
printing::PrintPreviewDialogController* controller =
printing::PrintPreviewDialogController::GetInstance();
return controller && (controller->GetPrintPreviewForContents(contents) ||
controller->is_creating_print_preview_dialog());
#else
return false;
#endif
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
} // namespace
bool IsCommandEnabled(Browser* browser, int command) {
return browser->command_controller()->IsCommandEnabled(command);
}
bool SupportsCommand(Browser* browser, int command) {
return browser->command_controller()->SupportsCommand(command);
}
bool ExecuteCommand(Browser* browser, int command, base::TimeTicks time_stamp) {
return browser->command_controller()->ExecuteCommand(command, time_stamp);
}
bool ExecuteCommandWithDisposition(Browser* browser,
int command,
WindowOpenDisposition disposition) {
return browser->command_controller()->ExecuteCommandWithDisposition(
command, disposition);
}
void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
browser->command_controller()->UpdateCommandEnabled(command, enabled);
}
void AddCommandObserver(Browser* browser,
int command,
CommandObserver* observer) {
browser->command_controller()->AddCommandObserver(command, observer);
}
void RemoveCommandObserver(Browser* browser,
int command,
CommandObserver* observer) {
browser->command_controller()->RemoveCommandObserver(command, observer);
}
int GetContentRestrictions(const Browser* browser) {
int content_restrictions = 0;
WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
if (current_tab) {
CoreTabHelper* core_tab_helper =
CoreTabHelper::FromWebContents(current_tab);
content_restrictions = core_tab_helper->content_restrictions();
NavigationEntry* last_committed_entry =
current_tab->GetController().GetLastCommittedEntry();
if (!content::IsSavableURL(
last_committed_entry ? last_committed_entry->GetURL() : GURL()))
content_restrictions |= CONTENT_RESTRICTION_SAVE;
}
return content_restrictions;
}
void NewEmptyWindow(Profile* profile, bool should_trigger_session_restore) {
bool off_the_record = profile->IsOffTheRecord();
PrefService* prefs = profile->GetPrefs();
if (off_the_record) {
if (IncognitoModePrefs::GetAvailability(prefs) ==
IncognitoModePrefs::Availability::kDisabled) {
off_the_record = false;
}
} else if (profile->IsGuestSession() ||
(browser_defaults::kAlwaysOpenIncognitoWindow &&
IncognitoModePrefs::ShouldLaunchIncognito(
*base::CommandLine::ForCurrentProcess(), prefs))) {
off_the_record = true;
}
if (off_the_record) {
// This metric counts the Incognito and Off-The-Record Guest profiles
// together.
base::RecordAction(UserMetricsAction("NewIncognitoWindow"));
if (profile->IsGuestSession())
base::RecordAction(UserMetricsAction("NewGuestWindow"));
else
base::RecordAction(UserMetricsAction("NewIncognitoWindow2"));
OpenEmptyWindow(profile->GetPrimaryOTRProfile(/*create_if_needed=*/true),
should_trigger_session_restore);
} else if (!should_trigger_session_restore) {
base::RecordAction(UserMetricsAction("NewWindow"));
OpenEmptyWindow(profile->GetOriginalProfile(),
/*should_trigger_session_restore=*/false);
} else {
base::RecordAction(UserMetricsAction("NewWindow"));
SessionService* session_service =
SessionServiceFactory::GetForProfileForSessionRestore(
profile->GetOriginalProfile());
if (!session_service ||
!session_service->RestoreIfNecessary(StartupTabs(),
/* restore_apps */ false)) {
OpenEmptyWindow(profile->GetOriginalProfile());
}
}
}
Browser* OpenEmptyWindow(Profile* profile,
bool should_trigger_session_restore) {
if (Browser::GetCreationStatusForProfile(profile) !=
Browser::CreationStatus::kOk) {
return nullptr;
}
Browser::CreateParams params =
Browser::CreateParams(Browser::TYPE_NORMAL, profile, true);
params.should_trigger_session_restore = should_trigger_session_restore;
Browser* browser = Browser::Create(params);
AddTabAt(browser, GURL(), -1, true);
browser->window()->Show();
return browser;
}
void OpenWindowWithRestoredTabs(Profile* profile) {
sessions::TabRestoreService* service =
TabRestoreServiceFactory::GetForProfile(profile);
if (service)
service->RestoreMostRecentEntry(nullptr);
}
void OpenURLOffTheRecord(Profile* profile, const GURL& url) {
ScopedTabbedBrowserDisplayer displayer(
profile->GetPrimaryOTRProfile(/*create_if_needed=*/true));
AddSelectedTabWithURL(displayer.browser(), url, ui::PAGE_TRANSITION_LINK);
}
bool CanGoBack(const Browser* browser) {
return browser->tab_strip_model()
->GetActiveWebContents()
->GetController()
.CanGoBack();
}
void GoBack(Browser* browser, WindowOpenDisposition disposition) {
base::RecordAction(UserMetricsAction("Back"));
if (CanGoBack(browser)) {
WebContents* new_tab = GetTabAndRevertIfNecessary(browser, disposition);
new_tab->GetController().GoBack();
}
}
bool CanGoForward(const Browser* browser) {
return browser->tab_strip_model()
->GetActiveWebContents()
->GetController()
.CanGoForward();
}
void GoForward(Browser* browser, WindowOpenDisposition disposition) {
base::RecordAction(UserMetricsAction("Forward"));
if (CanGoForward(browser)) {
GetTabAndRevertIfNecessary(browser, disposition)
->GetController()
.GoForward();
}
}
void NavigateToIndexWithDisposition(Browser* browser,
int index,
WindowOpenDisposition disposition) {
NavigationController* controller =
&GetTabAndRevertIfNecessary(browser, disposition)->GetController();
DCHECK_GE(index, 0);
DCHECK_LT(index, controller->GetEntryCount());
controller->GoToIndex(index);
}
void Reload(Browser* browser, WindowOpenDisposition disposition) {
base::RecordAction(UserMetricsAction("Reload"));
ReloadInternal(browser, disposition, false);
}
void ReloadBypassingCache(Browser* browser, WindowOpenDisposition disposition) {
base::RecordAction(UserMetricsAction("ReloadBypassingCache"));
ReloadInternal(browser, disposition, true);
}
bool CanReload(const Browser* browser) {
return browser && !browser->is_type_devtools();
}
void Home(Browser* browser, WindowOpenDisposition disposition) {
base::RecordAction(UserMetricsAction("Home"));
std::string extra_headers;
#if BUILDFLAG(ENABLE_RLZ)
// If the home page is a Google home page, add the RLZ header to the request.
PrefService* pref_service = browser->profile()->GetPrefs();
if (pref_service) {
if (google_util::IsGoogleHomePageUrl(
GURL(pref_service->GetString(prefs::kHomePage)))) {
extra_headers = rlz::RLZTracker::GetAccessPointHttpHeader(
rlz::RLZTracker::ChromeHomePage());
}
}
#endif // BUILDFLAG(ENABLE_RLZ)
GURL url = browser->profile()->GetHomePage();
#if BUILDFLAG(ENABLE_EXTENSIONS)
// With bookmark apps enabled, hosted apps should return to their launch page
// when the home button is pressed.
if (browser->is_type_app() || browser->is_type_app_popup()) {
const extensions::Extension* extension = GetExtensionForBrowser(browser);
if (!extension)
return;
url = extensions::AppLaunchInfo::GetLaunchWebURL(extension);
}
if (disposition == WindowOpenDisposition::CURRENT_TAB ||
disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB)
extensions::MaybeShowExtensionControlledHomeNotification(browser);
#endif
bool is_chrome_internal = url.SchemeIs(url::kAboutScheme) ||
url.SchemeIs(content::kChromeUIScheme) ||
url.SchemeIs(chrome::kChromeNativeScheme);
base::UmaHistogramBoolean("Navigation.Home.IsChromeInternal",
is_chrome_internal);
// Log a user action for the !is_chrome_internal case. This value is used as
// part of a high-level guiding metric, which is being migrated to user
// actions.
if (!is_chrome_internal) {
base::RecordAction(
base::UserMetricsAction("Navigation.Home.NotChromeInternal"));
}
OpenURLParams params(
url, Referrer(), disposition,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_BOOKMARK |
ui::PAGE_TRANSITION_HOME_PAGE),
false);
params.extra_headers = extra_headers;
browser->OpenURL(params);
}
base::WeakPtr<content::NavigationHandle> OpenCurrentURL(Browser* browser) {
base::RecordAction(UserMetricsAction("LoadURL"));
// TODO(https://crbug.com/1294004): Eliminate extra checks once source of
// bad pointer dereference is identified. See also TODO comment below.
CHECK(browser);
BrowserWindow* window = browser->window();
CHECK(window);
LocationBar* location_bar = window->GetLocationBar();
if (!location_bar) {
return nullptr;
}
GURL url(location_bar->GetDestinationURL());
TRACE_EVENT1("navigation", "chrome::OpenCurrentURL", "url", url);
if (ShouldInterceptChromeURLNavigationInIncognito(browser, url)) {
ProcessInterceptedChromeURLNavigationInIncognito(browser, url);
return nullptr;
}
NavigateParams params(browser, url, location_bar->GetPageTransition());
params.disposition = location_bar->GetWindowOpenDisposition();
// Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
// inherit the opener. In some cases the tabstrip will determine the group
// should be inherited, in which case the group is inherited instead of the
// opener.
params.tabstrip_add_types =
TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
params.input_start = location_bar->GetMatchSelectionTimestamp();
params.is_using_https_as_default_scheme =
location_bar->IsInputTypedUrlWithoutScheme();
auto result = Navigate(&params);
#if BUILDFLAG(ENABLE_EXTENSIONS)
DCHECK(extensions::ExtensionSystem::Get(browser->profile())
->extension_service());
// TODO(https://crbug.com/1294004): Eliminate extra checks once source of
// bad pointer dereference is identified. See also TODO comment above.
extensions::ExtensionRegistry* extension_registry =
extensions::ExtensionRegistry::Get(browser->profile());
CHECK(extension_registry);
const extensions::Extension* extension =
extension_registry->enabled_extensions().GetAppByURL(url);
if (extension) {
extensions::RecordAppLaunchType(extension_misc::APP_LAUNCH_OMNIBOX_LOCATION,
extension->GetType());
}
#endif
return result;
}
void Stop(Browser* browser) {
base::RecordAction(UserMetricsAction("Stop"));
browser->tab_strip_model()->GetActiveWebContents()->Stop();
}
void NewWindow(Browser* browser) {
Profile* const profile = browser->profile();
#if BUILDFLAG(IS_MAC)
// Web apps should open a window to their launch page.
if (browser->app_controller()) {
const web_app::AppId app_id = browser->app_controller()->app_id();
auto launch_container =
apps::mojom::LaunchContainer::kLaunchContainerWindow;
auto* provider = web_app::WebAppProvider::GetForWebApps(profile);
if (provider && provider->registrar().GetAppEffectiveDisplayMode(app_id) ==
blink::mojom::DisplayMode::kBrowser) {
launch_container = apps::mojom::LaunchContainer::kLaunchContainerTab;
}
apps::AppLaunchParams params = apps::AppLaunchParams(
app_id, launch_container, WindowOpenDisposition::NEW_WINDOW,
apps::mojom::LaunchSource::kFromKeyboard);
apps::AppServiceProxyFactory::GetForProfile(profile)
->BrowserAppLauncher()
->LaunchAppWithParams(std::move(params));
return;
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
// Hosted apps should open a window to their launch page.
const extensions::Extension* extension = GetExtensionForBrowser(browser);
if (extension && extension->is_hosted_app()) {
const auto app_launch_params = CreateAppLaunchParamsUserContainer(
profile, extension, WindowOpenDisposition::NEW_WINDOW,
apps::mojom::LaunchSource::kFromKeyboard);
OpenApplicationWindow(
profile, app_launch_params,
extensions::AppLaunchInfo::GetLaunchWebURL(extension));
return;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(IS_MAC)
NewEmptyWindow(profile->GetOriginalProfile());
}
void NewIncognitoWindow(Profile* profile) {
NewEmptyWindow(profile->GetPrimaryOTRProfile(/*create_if_needed=*/true));
}
void CloseWindow(Browser* browser) {
base::RecordAction(UserMetricsAction("CloseWindow"));
browser->window()->Close();
}
void NewTab(Browser* browser) {
base::RecordAction(UserMetricsAction("NewTab"));
// TODO(asvitkine): This is invoked programmatically from several places.
// Audit the code and change it so that the histogram only gets collected for
// user-initiated commands.
UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
TabStripModel::NEW_TAB_ENUM_COUNT);
// Notify IPH that new tab was opened.
auto* reopen_tab_iph =
ReopenTabInProductHelpFactory::GetForProfile(browser->profile());
reopen_tab_iph->NewTabOpened();
if (browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)) {
AddTabAt(browser, GURL(), -1, true);
} else {
ScopedTabbedBrowserDisplayer displayer(browser->profile());
Browser* b = displayer.browser();
AddTabAt(b, GURL(), -1, true);
b->window()->Show();
// The call to AddBlankTabAt above did not set the focus to the tab as its
// window was not active, so we have to do it explicitly.
// See http://crbug.com/6380.
b->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
}
}
void NewTabToRight(Browser* browser) {
browser->tab_strip_model()->ExecuteContextMenuCommand(
browser->tab_strip_model()->active_index(),
TabStripModel::CommandNewTabToRight);
}
void CloseTab(Browser* browser) {
base::RecordAction(UserMetricsAction("CloseTab_Accelerator"));
browser->tab_strip_model()->CloseSelectedTabs();
}
bool CanZoomIn(content::WebContents* contents) {
return contents && !contents->IsCrashed() &&
zoom::ZoomController::FromWebContents(contents)->GetZoomPercent() !=
contents->GetMaximumZoomPercent();
}
bool CanZoomOut(content::WebContents* contents) {
return contents && !contents->IsCrashed() &&
zoom::ZoomController::FromWebContents(contents)->GetZoomPercent() !=
contents->GetMinimumZoomPercent();
}
bool CanResetZoom(content::WebContents* contents) {
zoom::ZoomController* zoom_controller =
zoom::ZoomController::FromWebContents(contents);
return !zoom_controller->IsAtDefaultZoom() ||
!zoom_controller->PageScaleFactorIsOne();
}
void SelectNextTab(Browser* browser,
TabStripUserGestureDetails gesture_detail) {
base::RecordAction(UserMetricsAction("SelectNextTab"));
browser->tab_strip_model()->SelectNextTab(gesture_detail);
}
void SelectPreviousTab(Browser* browser,
TabStripUserGestureDetails gesture_detail) {
base::RecordAction(UserMetricsAction("SelectPrevTab"));
browser->tab_strip_model()->SelectPreviousTab(gesture_detail);
}
void MoveTabNext(Browser* browser) {
base::RecordAction(UserMetricsAction("MoveTabNext"));
browser->tab_strip_model()->MoveTabNext();
}
void MoveTabPrevious(Browser* browser) {
base::RecordAction(UserMetricsAction("MoveTabPrevious"));
browser->tab_strip_model()->MoveTabPrevious();
}
void SelectNumberedTab(Browser* browser,
int index,
TabStripUserGestureDetails gesture_detail) {
int visible_count = 0;
for (int i = 0; i < browser->tab_strip_model()->count(); i++) {
if (browser->tab_strip_model()->IsTabCollapsed(i)) {
continue;
}
if (visible_count == index) {
base::RecordAction(UserMetricsAction("SelectNumberedTab"));
browser->tab_strip_model()->ActivateTabAt(i, gesture_detail);
break;
}
visible_count += 1;
}
}
void SelectLastTab(Browser* browser,
TabStripUserGestureDetails gesture_detail) {
for (int i = browser->tab_strip_model()->count() - 1; i >= 0; i--) {
if (!browser->tab_strip_model()->IsTabCollapsed(i)) {
base::RecordAction(UserMetricsAction("SelectLastTab"));
browser->tab_strip_model()->ActivateTabAt(i, gesture_detail);
break;
}
}
}
void DuplicateTab(Browser* browser) {
base::RecordAction(UserMetricsAction("Duplicate"));
DuplicateTabAt(browser, browser->tab_strip_model()->active_index());
}
bool CanDuplicateTab(const Browser* browser) {
return CanDuplicateTabAt(browser, browser->tab_strip_model()->active_index());
}
bool CanDuplicateKeyboardFocusedTab(const Browser* browser) {
if (!HasKeyboardFocusedTab(browser))
return false;
return CanDuplicateTabAt(browser, *GetKeyboardFocusedTabIndex(browser));
}
bool CanMoveActiveTabToNewWindow(Browser* browser) {
const ui::ListSelectionModel::SelectedIndices& selection =
browser->tab_strip_model()->selection_model().selected_indices();
return CanMoveTabsToNewWindow(
browser, std::vector<int>(selection.begin(), selection.end()));
}
void MoveActiveTabToNewWindow(Browser* browser) {
const ui::ListSelectionModel::SelectedIndices& selection =
browser->tab_strip_model()->selection_model().selected_indices();
MoveTabsToNewWindow(browser,
std::vector<int>(selection.begin(), selection.end()));
}
bool CanMoveTabsToNewWindow(Browser* browser,
const std::vector<int>& tab_indices) {
return browser->tab_strip_model()->count() >
static_cast<int>(tab_indices.size());
}
void MoveTabsToNewWindow(Browser* browser,
const std::vector<int>& tab_indices,
absl::optional<tab_groups::TabGroupId> group) {
if (tab_indices.empty())
return;
Browser* new_browser =
Browser::Create(Browser::CreateParams(browser->profile(), true));
if (group.has_value()) {
const tab_groups::TabGroupVisualData* old_visual_data =
browser->tab_strip_model()
->group_model()
->GetTabGroup(group.value())
->visual_data();
tab_groups::TabGroupVisualData new_visual_data(old_visual_data->title(),
old_visual_data->color(),
false /* is_collapsed */);
new_browser->tab_strip_model()->group_model()->AddTabGroup(group.value(),
new_visual_data);
}
int indices_size = tab_indices.size();
int active_index = browser->tab_strip_model()->active_index();
for (int i = 0; i < indices_size; i++) {
// Adjust tab index to account for tabs already moved.
int adjusted_index = tab_indices[i] - i;
bool pinned = browser->tab_strip_model()->IsTabPinned(adjusted_index);
std::unique_ptr<WebContents> contents_move =
browser->tab_strip_model()->DetachWebContentsAtForInsertion(
adjusted_index);
int add_types = pinned ? TabStripModel::ADD_PINNED : 0;
// The last tab made active takes precedence, so activate the last active
// tab, with a fallback for the first tab (i == 0) if the active tab isn’t
// in the set of tabs being moved.
if (i == 0 || tab_indices[i] == active_index)
add_types = add_types | TabStripModel::ADD_ACTIVE;
new_browser->tab_strip_model()->AddWebContents(std::move(contents_move), -1,
ui::PAGE_TRANSITION_TYPED,
add_types, group);
}
new_browser->window()->Show();
}
bool CanCloseTabsToRight(const Browser* browser) {
return browser->tab_strip_model()->IsContextMenuCommandEnabled(
browser->tab_strip_model()->active_index(),
TabStripModel::CommandCloseTabsToRight);
}
bool CanCloseOtherTabs(const Browser* browser) {
return browser->tab_strip_model()->IsContextMenuCommandEnabled(
browser->tab_strip_model()->active_index(),
TabStripModel::CommandCloseOtherTabs);
}
WebContents* DuplicateTabAt(Browser* browser, int index) {
WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index);
CHECK(contents);
std::unique_ptr<WebContents> contents_dupe = contents->Clone();
WebContents* raw_contents_dupe = contents_dupe.get();
bool pinned = false;
if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
// If this is a tabbed browser, just create a duplicate tab inside the same
// window next to the tab being duplicated.
TabStripModel* tab_strip_model = browser->tab_strip_model();
const int contents_index = tab_strip_model->GetIndexOfWebContents(contents);
pinned = tab_strip_model->IsTabPinned(contents_index);
int add_types = TabStripModel::ADD_ACTIVE |
TabStripModel::ADD_INHERIT_OPENER |
(pinned ? TabStripModel::ADD_PINNED : 0);
const auto old_group = tab_strip_model->GetTabGroupForTab(contents_index);
tab_strip_model->InsertWebContentsAt(
contents_index + 1, std::move(contents_dupe), add_types, old_group);
} else {
CreateAndShowNewWindowWithContents(std::move(contents_dupe), browser);
}
SessionServiceBase* session_service =
GetAppropriateSessionServiceIfExisting(browser);
if (session_service)
session_service->TabRestored(raw_contents_dupe, pinned);
return raw_contents_dupe;
}
bool CanDuplicateTabAt(const Browser* browser, int index) {
WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index);
return contents && contents->GetController().GetLastCommittedEntry();
}
void MoveTabsToExistingWindow(Browser* source,
Browser* target,
const std::vector<int>& tab_indices) {
if (tab_indices.empty())
return;
int indices_size = tab_indices.size();
for (int i = 0; i < indices_size; i++) {
// Adjust tab index to account for tabs already moved.
int adjusted_index = tab_indices[i] - i;
bool pinned = source->tab_strip_model()->IsTabPinned(adjusted_index);
std::unique_ptr<WebContents> contents_move =
source->tab_strip_model()->DetachWebContentsAtForInsertion(
adjusted_index);
int add_types = TabStripModel::ADD_ACTIVE |
(pinned ? TabStripModel::ADD_PINNED : 0);
target->tab_strip_model()->AddWebContents(
std::move(contents_move), -1, ui::PAGE_TRANSITION_TYPED, add_types);
}
target->window()->Show();
}
void PinTab(Browser* browser) {
browser->tab_strip_model()->ExecuteContextMenuCommand(
browser->tab_strip_model()->active_index(),
TabStripModel::ContextMenuCommand::CommandTogglePinned);
}
void GroupTab(Browser* browser) {
browser->tab_strip_model()->ExecuteContextMenuCommand(
browser->tab_strip_model()->active_index(),
TabStripModel::ContextMenuCommand::CommandToggleGrouped);
}
void MuteSite(Browser* browser) {
browser->tab_strip_model()->ExecuteContextMenuCommand(
browser->tab_strip_model()->active_index(),
TabStripModel::ContextMenuCommand::CommandToggleSiteMuted);
}
void MuteSiteForKeyboardFocusedTab(Browser* browser) {
if (!HasKeyboardFocusedTab(browser))
return;
browser->tab_strip_model()->ExecuteContextMenuCommand(
*GetKeyboardFocusedTabIndex(browser),
TabStripModel::ContextMenuCommand::CommandToggleSiteMuted);
}
void PinKeyboardFocusedTab(Browser* browser) {
if (!HasKeyboardFocusedTab(browser))
return;
browser->tab_strip_model()->ExecuteContextMenuCommand(
*GetKeyboardFocusedTabIndex(browser),
TabStripModel::ContextMenuCommand::CommandTogglePinned);
}
void GroupKeyboardFocusedTab(Browser* browser) {
if (!HasKeyboardFocusedTab(browser))
return;
browser->tab_strip_model()->ExecuteContextMenuCommand(
*GetKeyboardFocusedTabIndex(browser),
TabStripModel::ContextMenuCommand::CommandToggleGrouped);
}
void DuplicateKeyboardFocusedTab(Browser* browser) {
if (HasKeyboardFocusedTab(browser)) {
DuplicateTabAt(browser, *GetKeyboardFocusedTabIndex(browser));
}
}
bool HasKeyboardFocusedTab(const Browser* browser) {
return GetKeyboardFocusedTabIndex(browser).has_value();
}
void ConvertPopupToTabbedBrowser(Browser* browser) {
base::RecordAction(UserMetricsAction("ShowAsTab"));
TabStripModel* tab_strip = browser->tab_strip_model();
std::unique_ptr<content::WebContents> contents =
tab_strip->DetachWebContentsAtForInsertion(tab_strip->active_index());
Browser* b = Browser::Create(Browser::CreateParams(browser->profile(), true));
b->tab_strip_model()->AppendWebContents(std::move(contents), true);
b->window()->Show();
}
void CloseTabsToRight(Browser* browser) {
browser->tab_strip_model()->ExecuteContextMenuCommand(
browser->tab_strip_model()->active_index(),
TabStripModel::CommandCloseTabsToRight);
}
void CloseOtherTabs(Browser* browser) {
browser->tab_strip_model()->ExecuteContextMenuCommand(
browser->tab_strip_model()->active_index(),
TabStripModel::CommandCloseOtherTabs);
}
void Exit() {
base::RecordAction(UserMetricsAction("Exit"));
chrome::AttemptUserExit();
}
void BookmarkCurrentTab(Browser* browser) {
base::RecordAction(UserMetricsAction("Star"));
BookmarkModel* model =
BookmarkModelFactory::GetForBrowserContext(browser->profile());
if (!model || !model->loaded())
return; // Ignore requests until bookmarks are loaded.
GURL url;
std::u16string title;
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
// |web_contents| can be nullptr if the last tab in the browser was closed
// but the browser wasn't closed yet. https://crbug.com/799668
if (!web_contents)
return;
if (!GetURLAndTitleToBookmark(web_contents, &url, &title))
return;
bool is_bookmarked_by_any = model->IsBookmarked(url);
if (!is_bookmarked_by_any &&
web_contents->GetBrowserContext()->IsOffTheRecord()) {
// If we're incognito the favicon may not have been saved. Save it now
// so that bookmarks have an icon for the page.
favicon::SaveFaviconEvenIfInIncognito(web_contents);
}
bool was_bookmarked_by_user = bookmarks::IsBookmarkedByUser(model, url);
bookmarks::AddIfNotBookmarked(model, url, title);
bool is_bookmarked_by_user = bookmarks::IsBookmarkedByUser(model, url);
// Make sure the model actually added a bookmark before showing the star. A
// bookmark isn't created if the url is invalid.
if (browser->window()->IsActive() && is_bookmarked_by_user) {
// Only show the bubble if the window is active, otherwise we may get into
// weird situations where the bubble is deleted as soon as it is shown.
browser->window()->ShowBookmarkBubble(url, was_bookmarked_by_user);
}
if (!was_bookmarked_by_user && is_bookmarked_by_user)
RecordBookmarksAdded(browser->profile());
}
bool CanBookmarkCurrentTab(const Browser* browser) {
BookmarkModel* model =
BookmarkModelFactory::GetForBrowserContext(browser->profile());
return browser_defaults::bookmarks_enabled &&
browser->profile()->GetPrefs()->GetBoolean(
bookmarks::prefs::kEditBookmarksEnabled) &&
model && model->loaded() && browser->is_type_normal();
}
void BookmarkAllTabs(Browser* browser) {
base::RecordAction(UserMetricsAction("BookmarkAllTabs"));
RecordBookmarkAllTabsWithTabsCount(browser->profile(),
browser->tab_strip_model()->count());
chrome::ShowBookmarkAllTabsDialog(browser);
}
bool CanBookmarkAllTabs(const Browser* browser) {
return browser->tab_strip_model()->count() > 1 &&
CanBookmarkCurrentTab(browser);
}
bool CanMoveActiveTabToReadLater(Browser* browser) {
GURL url;
std::u16string title;
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
ReadingListModel* model = GetReadingListModel(browser);
return CanMoveWebContentsToReadLater(browser, web_contents, model, &url,
&title);
}
bool MoveCurrentTabToReadLater(Browser* browser) {
return MoveTabToReadLater(browser,
browser->tab_strip_model()->GetActiveWebContents());
}
bool MoveTabToReadLater(Browser* browser, content::WebContents* web_contents) {
GURL url;
std::u16string title;
ReadingListModel* model = GetReadingListModel(browser);
if (!CanMoveWebContentsToReadLater(browser, web_contents, model, &url,
&title)) {
return false;
}
model->AddEntry(url, base::UTF16ToUTF8(title),
reading_list::EntrySource::ADDED_VIA_CURRENT_APP);
browser->window()->MaybeShowFeaturePromo(
feature_engagement::kIPHReadingListDiscoveryFeature);
base::UmaHistogramEnumeration(
"ReadingList.BookmarkBarState.OnEveryAddToReadingList",
browser->bookmark_bar_state());
return true;
}
bool MarkCurrentTabAsReadInReadLater(Browser* browser) {
GURL url;
std::u16string title;
ReadingListModel* model = GetReadingListModel(browser);
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
if (!model || !GetTabURLAndTitleToSave(web_contents, &url, &title))
return false;
const ReadingListEntry* entry = model->GetEntryByURL(url);
// Mark current tab as read.
if (entry && !entry->IsRead())
model->SetReadStatus(url, true);
return entry != nullptr;
}
bool IsCurrentTabUnreadInReadLater(Browser* browser) {
GURL url;
std::u16string title;
ReadingListModel* model = GetReadingListModel(browser);
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
if (!model || !GetTabURLAndTitleToSave(web_contents, &url, &title))
return false;
const ReadingListEntry* entry = model->GetEntryByURL(url);
return entry && !entry->IsRead();
}
void ShowOffersAndRewardsForPage(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
autofill::OfferNotificationBubbleControllerImpl* controller =
autofill::OfferNotificationBubbleControllerImpl::FromWebContents(
web_contents);
DCHECK(controller);
controller->ReshowBubble();
}
void SaveCreditCard(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
autofill::SaveCardBubbleControllerImpl* controller =
autofill::SaveCardBubbleControllerImpl::FromWebContents(web_contents);
controller->ReshowBubble();
}
void MigrateLocalCards(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
autofill::ManageMigrationUiController* controller =
autofill::ManageMigrationUiController::FromWebContents(web_contents);
// Show migration-related Ui when the user clicks the credit card icon.
controller->OnUserClickedCreditCardIcon();
}
void SaveAutofillAddress(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
autofill::SaveUpdateAddressProfileBubbleControllerImpl* controller =
autofill::SaveUpdateAddressProfileBubbleControllerImpl::FromWebContents(
web_contents);
controller->OnPageActionIconClicked();
}
void ShowVirtualCardManualFallbackBubble(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
auto* controller =
autofill::VirtualCardManualFallbackBubbleControllerImpl::FromWebContents(
web_contents);
if (controller)
controller->ReshowBubble();
}
void ShowVirtualCardEnrollBubble(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
autofill::VirtualCardEnrollBubbleControllerImpl* controller =
autofill::VirtualCardEnrollBubbleControllerImpl::FromWebContents(
web_contents);
if (controller)
controller->ReshowBubble();
}
void Translate(Browser* browser) {
if (!browser->window()->IsActive())
return;
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
ChromeTranslateClient* chrome_translate_client =
ChromeTranslateClient::FromWebContents(web_contents);
std::string source_language;
std::string target_language;
chrome_translate_client->GetTranslateLanguages(web_contents, &source_language,
&target_language);
translate::TranslateStep step = translate::TRANSLATE_STEP_BEFORE_TRANSLATE;
if (chrome_translate_client) {
if (chrome_translate_client->GetLanguageState().translation_pending())
step = translate::TRANSLATE_STEP_TRANSLATING;
else if (chrome_translate_client->GetLanguageState().translation_error())
step = translate::TRANSLATE_STEP_TRANSLATE_ERROR;
else if (chrome_translate_client->GetLanguageState().IsPageTranslated())
step = translate::TRANSLATE_STEP_AFTER_TRANSLATE;
}
ShowTranslateBubbleResult result = browser->window()->ShowTranslateBubble(
web_contents, step, source_language, target_language,
translate::TranslateErrors::NONE, true);
if (result != ShowTranslateBubbleResult::SUCCESS)
translate::ReportTranslateBubbleUiAction(
TranslateBubbleResultToUiEvent(result));
}
void ManagePasswordsForPage(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
ManagePasswordsUIController* controller =
ManagePasswordsUIController::FromWebContents(web_contents);
TabDialogs::FromWebContents(web_contents)
->ShowManagePasswordsBubble(!controller->IsAutomaticallyOpeningBubble());
}
void SendTabToSelfFromPageAction(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
send_tab_to_self::SendTabToSelfBubbleController* controller =
send_tab_to_self::SendTabToSelfBubbleController::
CreateOrGetFromWebContents(web_contents);
controller->ShowBubble();
}
void GenerateQRCodeFromPageAction(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
qrcode_generator::QRCodeGeneratorBubbleController* controller =
qrcode_generator::QRCodeGeneratorBubbleController::Get(web_contents);
content::NavigationEntry* entry =
web_contents->GetController().GetLastCommittedEntry();
controller->ShowBubble(entry->GetURL());
}
void SharingHubFromPageAction(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
sharing_hub::SharingHubBubbleController* controller =
sharing_hub::SharingHubBubbleController::CreateOrGetFromWebContents(
web_contents);
controller->ShowBubble(share::ShareAttempt(web_contents));
}
void ScreenshotCaptureFromPageAction(Browser* browser) {
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
sharing_hub::ScreenshotCapturedBubbleController* controller =
sharing_hub::ScreenshotCapturedBubbleController::Get(web_contents);
controller->Capture(browser);
}
void SavePage(Browser* browser) {
base::RecordAction(UserMetricsAction("SavePage"));
WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
DCHECK(current_tab);
if (current_tab->GetContentsMimeType() == "application/pdf")
base::RecordAction(UserMetricsAction("PDF.SavePage"));
current_tab->OnSavePage();
}
bool CanSavePage(const Browser* browser) {
// LocalState can be NULL in tests.
if (g_browser_process->local_state() &&
!g_browser_process->local_state()->GetBoolean(
prefs::kAllowFileSelectionDialogs)) {
return false;
}
if (static_cast<DownloadPrefs::DownloadRestriction>(
browser->profile()->GetPrefs()->GetInteger(
prefs::kDownloadRestrictions)) ==
DownloadPrefs::DownloadRestriction::ALL_FILES) {
return false;
}
return !browser->is_type_devtools() &&
!(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE);
}
void Print(Browser* browser) {
#if BUILDFLAG(ENABLE_PRINTING)
auto* web_contents = browser->tab_strip_model()->GetActiveWebContents();
printing::StartPrint(
web_contents, mojo::NullAssociatedRemote() /* print_renderer */,
browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled),
false /* has_selection? */);
#endif
}
bool CanPrint(Browser* browser) {
#if BUILDFLAG(ENABLE_PRINTING)
// Do not print when printing is disabled via pref or policy.
// Do not print when a page has crashed.
// Do not print when a constrained window is showing. It's confusing.
// TODO(gbillock): Need to re-assess the call to
// IsShowingWebContentsModalDialog after a popup management policy is
// refined -- we will probably want to just queue the print request, not
// block it.
WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
(current_tab && !current_tab->IsCrashed()) &&
!(IsShowingWebContentsModalDialog(browser) ||
GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT);
#else // BUILDFLAG(ENABLE_PRINTING)
return false;
#endif // BUILDFLAG(ENABLE_PRINTING)
}
#if BUILDFLAG(ENABLE_PRINTING)
void BasicPrint(Browser* browser) {
printing::StartBasicPrint(browser->tab_strip_model()->GetActiveWebContents());
}
bool CanBasicPrint(Browser* browser) {
#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
// If printing is not disabled via pref or policy, it is always possible to
// advanced print when the print preview is visible.
return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
(PrintPreviewShowing(browser) || CanPrint(browser));
#else
return false; // The print dialog is disabled.
#endif // BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
}
#endif // BUILDFLAG(ENABLE_PRINTING)
bool CanRouteMedia(Browser* browser) {
// Do not allow user to open Media Router dialog when there is already an
// active modal dialog. This avoids overlapping dialogs.
return media_router::MediaRouterEnabled(browser->profile()) &&
!IsShowingWebContentsModalDialog(browser);
}
void RouteMediaInvokedFromAppMenu(Browser* browser) {
DCHECK(CanRouteMedia(browser));
media_router::MediaRouterDialogController* dialog_controller =
media_router::MediaRouterDialogController::GetOrCreateForWebContents(
browser->tab_strip_model()->GetActiveWebContents());
if (!dialog_controller)
return;
dialog_controller->ShowMediaRouterDialog(
media_router::MediaRouterDialogOpenOrigin::APP_MENU);
}
void CutCopyPaste(Browser* browser, int command_id) {
if (command_id == IDC_CUT)
base::RecordAction(UserMetricsAction("Cut"));
else if (command_id == IDC_COPY)
base::RecordAction(UserMetricsAction("Copy"));
else
base::RecordAction(UserMetricsAction("Paste"));
browser->window()->CutCopyPaste(command_id);
}
void Find(Browser* browser) {
base::RecordAction(UserMetricsAction("Find"));
FindInPage(browser, false, true);
}
void FindNext(Browser* browser) {
base::RecordAction(UserMetricsAction("FindNext"));
FindInPage(browser, true, true);
}
void FindPrevious(Browser* browser) {
base::RecordAction(UserMetricsAction("FindPrevious"));
FindInPage(browser, true, false);
}
void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
browser->GetFindBarController()->Show(find_next, forward_direction);
}
void ShowTabSearch(Browser* browser) {
browser->window()->CreateTabSearchBubble();
}
void CloseTabSearch(Browser* browser) {
browser->window()->CloseTabSearchBubble();
}
bool CanCloseFind(Browser* browser) {
WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
if (!current_tab)
return false;
find_in_page::FindTabHelper* find_helper =
find_in_page::FindTabHelper::FromWebContents(current_tab);
return find_helper ? find_helper->find_ui_active() : false;
}
void CloseFind(Browser* browser) {
browser->GetFindBarController()->EndFindSession(
find_in_page::SelectionAction::kKeep, find_in_page::ResultAction::kKeep);
}
void Zoom(Browser* browser, content::PageZoom zoom) {
zoom::PageZoom::Zoom(browser->tab_strip_model()->GetActiveWebContents(),
zoom);
}
void FocusToolbar(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusToolbar"));
browser->window()->FocusToolbar();
}
void FocusLocationBar(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusLocation"));
browser->window()->SetFocusToLocationBar(true);
}
void FocusSearch(Browser* browser) {
// TODO(beng): replace this with FocusLocationBar
base::RecordAction(UserMetricsAction("FocusSearch"));
browser->window()->GetLocationBar()->FocusSearch();
}
void FocusAppMenu(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusAppMenu"));
browser->window()->FocusAppMenu();
}
void FocusBookmarksToolbar(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
browser->window()->FocusBookmarksToolbar();
}
void FocusInactivePopupForAccessibility(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusInactivePopupForAccessibility"));
browser->window()->FocusInactivePopupForAccessibility();
}
void FocusNextPane(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusNextPane"));
browser->window()->RotatePaneFocus(true);
}
void FocusPreviousPane(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusPreviousPane"));
browser->window()->RotatePaneFocus(false);
}
void FocusWebContentsPane(Browser* browser) {
base::RecordAction(UserMetricsAction("FocusWebContentsPane"));
browser->window()->FocusWebContentsPane();
}
void ToggleDevToolsWindow(Browser* browser,
DevToolsToggleAction action,
DevToolsOpenedByAction opened_by) {
if (action.type() == DevToolsToggleAction::kShowConsolePanel)
base::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
else
base::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
DevToolsWindow::ToggleDevToolsWindow(browser, action, opened_by);
}
bool CanOpenTaskManager() {
#if !BUILDFLAG(IS_ANDROID)
return true;
#else
return false;
#endif
}
void OpenTaskManager(Browser* browser) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Open linux version of task manager UI if ash TaskManager
// interface is in an old version.
if (chromeos::LacrosService::Get()->GetInterfaceVersion(
crosapi::mojom::TaskManager::Uuid_) < 1) {
base::RecordAction(UserMetricsAction("TaskManager"));
chrome::ShowTaskManager(browser);
return;
}
// Invoke task manager UI in ash, which will call chrome::OpenTaskManager()
// in ash to run through the code path in the next section
// (!BUILDFLAG(IS_ANDROID)).
chromeos::LacrosService::Get()
->GetRemote<crosapi::mojom::TaskManager>()
->ShowTaskManager();
#elif !BUILDFLAG(IS_ANDROID)
base::RecordAction(UserMetricsAction("TaskManager"));
chrome::ShowTaskManager(browser);
#else
NOTREACHED();
#endif
}
void OpenFeedbackDialog(Browser* browser,
FeedbackSource source,
const std::string& description_template) {
base::RecordAction(UserMetricsAction("Feedback"));
chrome::ShowFeedbackPage(browser, source, description_template,
std::string() /* description_placeholder_text */,
std::string() /* category_tag */,
std::string() /* extra_diagnostics */);
}
void ToggleBookmarkBar(Browser* browser) {
base::RecordAction(UserMetricsAction("ShowBookmarksBar"));
ToggleBookmarkBarWhenVisible(browser->profile());
}
void ToggleShowFullURLs(Browser* browser) {
bool pref_enabled = browser->profile()->GetPrefs()->GetBoolean(
omnibox::kPreventUrlElisionsInOmnibox);
browser->profile()->GetPrefs()->SetBoolean(
omnibox::kPreventUrlElisionsInOmnibox, !pref_enabled);
}
void ShowAppMenu(Browser* browser) {
// We record the user metric for this event in AppMenu::RunMenu.
browser->window()->ShowAppMenu();
}
void ShowAvatarMenu(Browser* browser) {
browser->window()->ShowAvatarBubbleFromAvatarButton(
/*is_source_accelerator=*/true);
}
void OpenUpdateChromeDialog(Browser* browser) {
if (UpgradeDetector::GetInstance()->is_outdated_install()) {
UpgradeDetector::GetInstance()->NotifyOutdatedInstall();
} else if (UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
UpgradeDetector::GetInstance()->NotifyOutdatedInstallNoAutoUpdate();
} else {
base::RecordAction(UserMetricsAction("UpdateChrome"));
browser->window()->ShowUpdateChromeDialog();
}
}
void ToggleDistilledView(Browser* browser) {
auto* current_web_contents =
browser->tab_strip_model()->GetActiveWebContents();
if (dom_distiller::url_utils::IsDistilledPage(
current_web_contents->GetLastCommittedURL())) {
ReturnToOriginalPage(current_web_contents);
} else {
DistillCurrentPageAndView(current_web_contents);
}
}
bool CanRequestTabletSite(WebContents* current_tab) {
return current_tab &&
current_tab->GetController().GetLastCommittedEntry() != nullptr;
}
bool IsRequestingTabletSite(Browser* browser) {
WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
if (!current_tab)
return false;
content::NavigationEntry* entry =
current_tab->GetController().GetLastCommittedEntry();
if (!entry)
return false;
return entry->GetIsOverridingUserAgent();
}
void ToggleRequestTabletSite(Browser* browser) {
WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
if (!current_tab)
return;
NavigationController& controller = current_tab->GetController();
NavigationEntry* entry = controller.GetLastCommittedEntry();
if (!entry)
return;
if (entry->GetIsOverridingUserAgent())
entry->SetIsOverridingUserAgent(false);
else
SetAndroidOsForTabletSite(current_tab);
controller.Reload(content::ReloadType::ORIGINAL_REQUEST_URL, true);
}
void SetAndroidOsForTabletSite(content::WebContents* current_tab) {
DCHECK(current_tab);
NavigationEntry* entry = current_tab->GetController().GetLastCommittedEntry();
if (entry) {
entry->SetIsOverridingUserAgent(true);
std::string product = embedder_support::GetProductAndVersion() + " Mobile";
blink::UserAgentOverride ua_override;
ua_override.ua_string_override = content::BuildUserAgentFromOSAndProduct(
kOsOverrideForTabletSite, product);
ua_override.ua_metadata_override = embedder_support::GetUserAgentMetadata(
g_browser_process->local_state());
ua_override.ua_metadata_override->mobile = true;
ua_override.ua_metadata_override->platform =
kChPlatformOverrideForTabletSite;
ua_override.ua_metadata_override->platform_version = std::string();
current_tab->SetUserAgentOverride(ua_override, false);
}
}
void ToggleFullscreenMode(Browser* browser) {
DCHECK(browser);
browser->exclusive_access_manager()
->fullscreen_controller()
->ToggleBrowserFullscreenMode();
}
void ClearCache(Browser* browser) {
content::BrowsingDataRemover* remover =
browser->profile()->GetBrowsingDataRemover();
remover->Remove(base::Time(), base::Time::Max(),
content::BrowsingDataRemover::DATA_TYPE_CACHE,
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB);
// BrowsingDataRemover takes care of deleting itself when done.
}
bool IsDebuggerAttachedToCurrentTab(Browser* browser) {
WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
return contents ? content::DevToolsAgentHost::IsDebuggerAttached(contents)
: false;
}
void CopyURL(Browser* browser) {
ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
scw.WriteText(base::UTF8ToUTF16(browser->tab_strip_model()
->GetActiveWebContents()
->GetVisibleURL()
.spec()));
}
Browser* OpenInChrome(Browser* hosted_app_browser) {
// Find a non-incognito browser.
Browser* target_browser =
chrome::FindTabbedBrowser(hosted_app_browser->profile(), false);
if (!target_browser) {
target_browser = Browser::Create(
Browser::CreateParams(hosted_app_browser->profile(), true));
}
TabStripModel* source_tabstrip = hosted_app_browser->tab_strip_model();
// Clear bounds once a PWA with window controls overlay display override opens
// in browser.
if (hosted_app_browser->app_controller()->IsWindowControlsOverlayEnabled()) {
source_tabstrip->GetActiveWebContents()->UpdateWindowControlsOverlay(
gfx::Rect());
}
target_browser->tab_strip_model()->AppendWebContents(
source_tabstrip->DetachWebContentsAtForInsertion(
source_tabstrip->active_index()),
true);
apps::MaybeShowIntentPicker(
target_browser->tab_strip_model()->GetActiveWebContents());
target_browser->window()->Show();
return target_browser;
}
bool CanViewSource(const Browser* browser) {
if (browser->is_type_devtools()) {
return false;
}
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
// Disallow ViewSource if DevTools are disabled.
if (!DevToolsWindow::AllowDevToolsFor(browser->profile(), web_contents)) {
return false;
}
return web_contents->GetController().CanViewSource();
}
bool CanToggleCaretBrowsing(Browser* browser) {
#if BUILDFLAG(IS_MAC)
// On Mac, ignore the keyboard shortcut unless web contents is focused,
// because the keyboard shortcut interferes with a Japenese IME when the
// omnibox is focused. See https://crbug.com/1138475
WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
if (!web_contents)
return false;
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
return rwhv && rwhv->HasFocus();
#else
return true;
#endif // BUILDFLAG(IS_MAC)
}
void ToggleCaretBrowsing(Browser* browser) {
if (!CanToggleCaretBrowsing(browser))
return;
PrefService* prefService = browser->profile()->GetPrefs();
bool enabled = prefService->GetBoolean(prefs::kCaretBrowsingEnabled);
if (enabled) {
base::RecordAction(base::UserMetricsAction(
"Accessibility.CaretBrowsing.DisableWithKeyboard"));
prefService->SetBoolean(prefs::kCaretBrowsingEnabled, false);
return;
}
// Show a confirmation dialog, unless either (1) the command-line
// flag was used, or (2) the user previously checked the box
// indicating not to ask them next time.
if (prefService->GetBoolean(prefs::kShowCaretBrowsingDialog) &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableCaretBrowsing)) {
browser->window()->ShowCaretBrowsingDialog();
} else {
base::RecordAction(base::UserMetricsAction(
"Accessibility.CaretBrowsing.EnableWithKeyboard"));
prefService->SetBoolean(prefs::kCaretBrowsingEnabled, true);
}
}
void PromptToNameWindow(Browser* browser) {
chrome::ShowWindowNamePrompt(browser);
}
void ToggleCommander(Browser* browser) {
commander::Commander::Get()->ToggleForBrowser(browser);
}
#if !defined(TOOLKIT_VIEWS)
absl::optional<int> GetKeyboardFocusedTabIndex(const Browser* browser) {
return absl::nullopt;
}
#endif
void ShowIncognitoClearBrowsingDataDialog(Browser* browser) {
browser->window()->ShowIncognitoClearBrowsingDataDialog();
}
void ShowIncognitoHistoryDisclaimerDialog(Browser* browser) {
browser->window()->ShowIncognitoHistoryDisclaimerDialog();
}
bool ShouldInterceptChromeURLNavigationInIncognito(Browser* browser,
const GURL& url) {
if (!browser || !browser->profile()->IsIncognitoProfile())
return false;
bool show_clear_browsing_data_dialog =
url == GURL(chrome::kChromeUISettingsURL)
.Resolve(chrome::kClearBrowserDataSubPage);
bool show_history_disclaimer_dialog =
url == GURL(chrome::kChromeUIHistoryURL) &&
base::FeatureList::IsEnabled(
features::kUpdateHistoryEntryPointsInIncognito);
return show_clear_browsing_data_dialog || show_history_disclaimer_dialog;
}
void ProcessInterceptedChromeURLNavigationInIncognito(Browser* browser,
const GURL& url) {
if (url == GURL(chrome::kChromeUISettingsURL)
.Resolve(chrome::kClearBrowserDataSubPage)) {
ShowIncognitoClearBrowsingDataDialog(browser);
} else if (url == GURL(chrome::kChromeUIHistoryURL)) {
DCHECK(base::FeatureList::IsEnabled(
features::kUpdateHistoryEntryPointsInIncognito));
ShowIncognitoHistoryDisclaimerDialog(browser);
} else {
NOTREACHED();
}
}
void FollowSite(content::WebContents* web_contents) {
DCHECK(!Profile::FromBrowserContext(web_contents->GetBrowserContext())
->IsIncognitoProfile());
feed::FollowSite(web_contents);
}
void UnfollowSite(content::WebContents* web_contents) {
DCHECK(!Profile::FromBrowserContext(web_contents->GetBrowserContext())
->IsIncognitoProfile());
feed::UnfollowSite(web_contents);
}
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void RunScreenAIVisualAnnotation(Browser* browser) {
browser->RunScreenAIAnnotator();
}
#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
} // namespace chrome