blob: 814c9d7913d30d0d5e745519fba94951ecb038ff [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/autofill/autofill_bubble_controller_base.h"
#include "chrome/browser/ui/autofill/autofill_bubble_base.h"
#include "chrome/browser/ui/autofill/bubble_manager.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/public/tab_features.h"
#include "chrome/browser/ui/views/page_action/page_action_controller.h"
#include "chrome/browser/ui/views/page_action/page_action_properties_provider.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/browser_window.h"
#endif // !BUILDFLAG(IS_ANDROID)
namespace autofill {
AutofillBubbleControllerBase::AutofillBubbleControllerBase(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {}
AutofillBubbleControllerBase::~AutofillBubbleControllerBase() {
if (IsShowingBubble()) {
bubble_view_->Hide();
bubble_view_ = nullptr;
}
}
void AutofillBubbleControllerBase::OnVisibilityChanged(
content::Visibility visibility) {
if (IsBubbleManagerEnabled()) {
// BubbleManager will handle the effects of tab changes.
return;
}
if (visibility == content::Visibility::HIDDEN) {
HideBubble(/*initiated_by_bubble_manager=*/false);
}
}
std::optional<PageActionIconType>
AutofillBubbleControllerBase::GetPageActionIconType() {
#if !BUILDFLAG(IS_ANDROID)
std::optional<actions::ActionId> action_id = GetActionIdForPageAction();
if (!action_id.has_value()) {
return std::nullopt;
}
page_actions::PageActionPropertiesProvider page_action_properties_provider;
if (!page_action_properties_provider.Contains(*action_id)) {
return std::nullopt;
}
const auto& properties =
page_action_properties_provider.GetProperties(*action_id);
return properties.type;
#else
return std::nullopt;
#endif //! BUILDFLAG(IS_ANDROID)
}
std::optional<actions::ActionId>
AutofillBubbleControllerBase::GetActionIdForPageAction() {
return std::nullopt;
}
void AutofillBubbleControllerBase::WebContentsDestroyed() {
if (IsShowingBubble()) {
bubble_view_->Hide();
bubble_view_ = nullptr;
}
}
bool AutofillBubbleControllerBase::ShouldShowPageAction() {
return IsShowingBubble();
}
std::optional<std::u16string>
AutofillBubbleControllerBase::GetPageActionTooltipText() {
return std::nullopt;
}
void AutofillBubbleControllerBase::UpdatePageActionIcon() {
// Page action icons do not exist for Android.
#if !BUILDFLAG(IS_ANDROID)
std::optional<PageActionIconType> icon_type = GetPageActionIconType();
if (!icon_type.has_value()) {
return;
}
std::optional<actions::ActionId> action_id = GetActionIdForPageAction();
// Legacy path for unmigrated page actions or when migration disabled by
// feature flag.
if (!action_id.has_value() || !IsPageActionMigrated(*icon_type)) {
if (Browser* browser = chrome::FindBrowserWithTab(web_contents())) {
browser->window()->UpdatePageActionIcon(*icon_type);
}
return;
}
tabs::TabInterface* const tab_interface =
tabs::TabInterface::MaybeGetFromContents(web_contents());
if (!tab_interface) {
return;
}
tabs::TabFeatures* const tab_features = tab_interface->GetTabFeatures();
// `TabFeatures` could be a nullptr if this method is called when the tab is
// being closed.
if (!tab_features) {
return;
}
// NOTE: Consider creating a separate page action view controller file
// when the logic to show the page action become complex.
page_actions::PageActionController* page_action_controller =
tab_features->page_action_controller();
if (!page_action_controller) {
return;
}
if (ShouldShowPageAction()) {
if (auto tooltip_text = GetPageActionTooltipText()) {
page_action_controller->OverrideText(*action_id, *tooltip_text);
page_action_controller->OverrideTooltip(*action_id, *tooltip_text);
}
page_action_controller->Show(*action_id);
} else {
page_action_controller->Hide(*action_id);
page_action_controller->ClearOverrideText(*action_id);
page_action_controller->ClearOverrideTooltip(*action_id);
}
#endif // !BUILDFLAG(IS_ANDROID)
}
void AutofillBubbleControllerBase::ShowBubble() {
was_bubble_shown_ = true;
UpdatePageActionIcon();
DoShowBubble();
UpdatePageActionIcon();
}
void AutofillBubbleControllerBase::HideBubble(
bool initiated_by_bubble_manager) {
if (IsShowingBubble()) {
bubble_hide_initiated_by_bubble_manager_ = initiated_by_bubble_manager;
bubble_view_->Hide();
ResetBubbleViewAndInformBubbleManager();
}
bubble_hide_initiated_by_bubble_manager_ = false;
}
bool AutofillBubbleControllerBase::CanBeReshown() const {
return true;
}
bool AutofillBubbleControllerBase::IsShowingBubble() const {
return bubble_view_ != nullptr;
}
bool AutofillBubbleControllerBase::IsMouseHovered() const {
return IsShowingBubble() && bubble_view_->IsMouseHovered();
}
bool AutofillBubbleControllerBase::MaySetUpBubble() {
#if BUILDFLAG(IS_ANDROID)
return true;
#else // BUILDFLAG(IS_ANDROID)
if (!IsBubbleManagerEnabled()) {
return true;
}
auto* manager = BubbleManager::GetForWebContents(web_contents());
return manager && !manager->HasPendingBubbleOfSameType(GetBubbleType());
#endif
}
void AutofillBubbleControllerBase::QueueOrShowBubble(bool force_show) {
#if !BUILDFLAG(IS_ANDROID)
if (IsBubbleManagerEnabled()) {
if (auto* manager = BubbleManager::GetForWebContents(web_contents())) {
manager->RequestShowController(*this, force_show);
}
return;
}
#endif
ShowBubble();
}
void AutofillBubbleControllerBase::SetBubbleView(
AutofillBubbleBase& bubble_view) {
bubble_view_ = &bubble_view;
}
void AutofillBubbleControllerBase::ResetBubbleViewAndInformBubbleManager() {
#if !BUILDFLAG(IS_ANDROID)
const bool was_showing = IsShowingBubble();
#endif // !BUILDFLAG(IS_ANDROID)
bubble_view_ = nullptr;
#if !BUILDFLAG(IS_ANDROID)
if (was_showing && base::FeatureList::IsEnabled(
features::kAutofillShowBubblesBasedOnPriorities)) {
if (auto* manager = BubbleManager::GetForWebContents(web_contents())) {
manager->OnBubbleHiddenByController(*this,
allow_bubble_manager_to_show_next_);
}
}
#endif // !BUILDFLAG(IS_ANDROID)
}
} // namespace autofill