blob: 78cf2cc970133cdbc972d30aecbfe81f2c4ed9e7 [file] [log] [blame]
// Copyright 2018 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/views/profiles/avatar_toolbar_button.h"
#include <vector>
#include "base/auto_reset.h"
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/notreached.h"
#include "base/observer_list.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/profiles/profile_colors_util.h"
#include "chrome/browser/ui/signin/dice_migration_service.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/profiles/avatar_toolbar_button_state_manager.h"
#include "chrome/browser/ui/views/profiles/profile_menu_coordinator.h"
#include "chrome/browser/ui/views/toolbar/toolbar_button.h"
#include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/feature_engagement/public/tracker.h"
#include "components/password_manager/content/common/web_ui_constants.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/base/signin_prefs.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/tribool.h"
#include "components/sync/base/features.h"
#include "components/user_education/common/user_education_class_properties.h"
#include "content/public/common/url_utils.h"
#include "google_apis/gaia/gaia_id.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/image_model_utils.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/theme_provider.h"
#include "ui/base/ui_base_features.h"
#include "ui/color/color_provider.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/button/button_controller.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/view_class_properties.h"
namespace {
constexpr int kChromeRefreshImageLabelPadding = 6;
// Value used to enlarge the AvatarIcon to accommodate for DIP scaling.
constexpr int kAvatarIconEnlargement = 1;
void UpdateProfileThemeColors(Browser* browser,
const ui::ColorProvider* color_provider) {
if (!color_provider) {
return;
}
CHECK(browser);
Profile* profile = browser->profile();
CHECK(profile);
if (profile->IsOffTheRecord() || profile->IsGuestSession()) {
return;
}
if (web_app::AppBrowserController::IsWebApp(browser)) {
return;
}
ProfileAttributesEntry* entry =
g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath());
if (!entry) {
return;
}
ThemeService* service = ThemeServiceFactory::GetForProfile(profile);
if (!service) {
return;
}
// Use default profile colors only for extension and system themes.
entry->SetProfileThemeColors(
ShouldUseDefaultProfileColors(*service)
? GetDefaultProfileThemeColors(color_provider)
: GetCurrentProfileThemeColors(*color_provider, *service));
}
} // namespace
// static
base::TimeDelta AvatarToolbarButton::g_iph_min_delay_after_creation =
base::Seconds(2);
AvatarToolbarButton::AvatarToolbarButton(BrowserView* browser_view)
: ToolbarButton(base::BindRepeating(&AvatarToolbarButton::ButtonPressed,
base::Unretained(this),
/*is_source_accelerator=*/false)),
browser_(browser_view->browser()),
creation_time_(base::TimeTicks::Now()) {
CHECK(browser_);
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(browser_->profile());
if (identity_manager) {
identity_manager_observation_.Observe(identity_manager);
}
#if BUILDFLAG(IS_CHROMEOS)
// On CrOS this button should only show as badging for Incognito, Guest and
// captivie portal signin. It's only enabled for non captive portal Incognito
// where a menu is available for closing all Incognito windows.
Profile* profile = browser_->profile();
CHECK(profile);
SetEnabled(profile->IsOffTheRecord() && !profile->IsGuestSession() &&
!profile->GetOTRProfileID().IsCaptivePortal());
#endif // BUILDFLAG(IS_CHROMEOS)
// Activate on press for left-mouse-button only to mimic other MenuButtons
// without drag-drop actions (specifically the adjacent browser menu).
button_controller()->set_notify_action(
views::ButtonController::NotifyAction::kOnPress);
SetTriggerableEventFlags(ui::EF_LEFT_MOUSE_BUTTON);
SetID(VIEW_ID_AVATAR_BUTTON);
SetProperty(views::kElementIdentifierKey, kToolbarAvatarButtonElementId);
// The avatar should not flip with RTL UI. This does not affect text rendering
// and LabelButton image/label placement is still flipped like usual.
SetFlipCanvasOnPaintForRTLUI(false);
GetViewAccessibility().SetHasPopup(ax::mojom::HasPopup::kMenu);
// For consistency with identity representation, we need to have the avatar on
// the left and the (potential) user name on the right.
SetHorizontalAlignment(gfx::ALIGN_LEFT);
SetImageLabelSpacing(kChromeRefreshImageLabelPadding);
label()->SetPaintToLayer();
label()->SetSkipSubpixelRenderingOpacityCheck(true);
label()->layer()->SetFillsBoundsOpaquely(false);
label()->SetSubpixelRenderingEnabled(false);
}
AvatarToolbarButton::~AvatarToolbarButton() = default;
void AvatarToolbarButton::UpdateIcon() {
// If the state manager isn't initialized, that means the widget is not set
// yet and the button doesn't have access to the theme provider to set colors.
// Defer updating until AddedToWidget(). This may get called as a result of
// OnUserIdentityChanged() called from the constructor when the button is not
// yet added to the ToolbarView's hierarchy.
if (!state_manager_) {
return;
}
const int icon_size = GetIconSize();
const ui::ColorProvider* const color_provider = GetColorProvider();
CHECK(color_provider);
StateProvider* state_provider = state_manager_->GetActiveStateProvider();
CHECK(state_provider);
ui::ImageModel icon = state_provider->GetAvatarIcon(
icon_size, GetForegroundColor(ButtonState::STATE_NORMAL),
*color_provider);
SetImageModel(ButtonState::STATE_NORMAL, icon);
SetImageModel(ButtonState::STATE_DISABLED,
ui::GetDefaultDisabledIconFromImageModel(icon));
observer_list_.Notify(&Observer::OnIconUpdated);
}
void AvatarToolbarButton::AddedToWidget() {
// `AddedToWidget()` can potentially be called more than once. E.g: on Mac
// when entering/exiting fullscreen.
if (!state_manager_) {
state_manager_ =
std::make_unique<AvatarToolbarButtonStateManager>(*this, browser_);
state_manager_->InitializeStates();
}
ToolbarButton::AddedToWidget();
// A call to `OnThemeChanged()` occurred before adding the widget, and could
// not be processed since the state manager was not initialized yet.
// This will also end up calling `UpdateIcon()`.
OnThemeChanged();
}
void AvatarToolbarButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
ToolbarButton::OnBoundsChanged(previous_bounds);
// This is needed to update the layout insets when the button is resized.
// `ToolbarButton::SetHighlight` may NOT clear the text immediately when the
// text is empty (clearing is delayed until the bounds are changed).
UpdateLayoutInsets();
}
void AvatarToolbarButton::Layout(PassKey) {
LayoutSuperclass<ToolbarButton>(this);
// TODO(crbug.com/40707582): this is a hack to avoid mismatch between avatar
// bitmap scaling and DIP->canvas pixel scaling in fractional DIP scaling
// modes (125%, 133%, etc.) that can cause the right-hand or bottom pixel row
// of the avatar image to be sliced off at certain specific browser sizes and
// configurations.
//
// In order to solve this, we increase the width and height of the image by 1
// after layout, so the rest of the layout is before. Since the profile image
// uses transparency, visually this does not cause any change in cases where
// the bug doesn't manifest.
auto* image = views::AsViewClass<views::ImageView>(image_container_view());
CHECK(image);
image->SetHorizontalAlignment(views::ImageView::Alignment::kLeading);
image->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
gfx::Size image_size = image->GetImage().size();
image_size.Enlarge(kAvatarIconEnlargement, kAvatarIconEnlargement);
image->SetSize(image_size);
}
void AvatarToolbarButton::UpdateText() {
CHECK(state_manager_);
StateProvider* state_provider = state_manager_->GetActiveStateProvider();
CHECK(state_provider);
const auto* const color_provider = GetColorProvider();
CHECK(color_provider);
SetTooltipText(state_provider->GetAvatarTooltipText());
SetHighlight(state_provider->GetText(),
state_provider->GetHighlightColor(*color_provider));
UpdateAccessibilityLabel();
// Update the layout insets after `SetHighlight()` since
// text might be updated by setting the highlight.
UpdateLayoutInsets();
UpdateInkdrop();
// Outset focus ring should be present for the chip but not when only
// the icon is visible, when there is no text.
views::FocusRing::Get(this)->SetOutsetFocusRingDisabled(
!IsLabelPresentAndVisible());
// TODO(crbug.com/40689215): this is a hack because toolbar buttons don't
// correctly calculate their preferred size until they've been laid out once
// or twice, because they modify their own borders and insets in response to
// their size and have their own preferred size caching mechanic. These should
// both ideally be handled with a modern layout manager instead.
//
// In the meantime, to ensure that correct (or nearly correct) bounds are set,
// we will force a resize then invalidate layout to let the layout manager
// take over.
SizeToPreferredSize();
InvalidateLayout();
}
void AvatarToolbarButton::UpdateAccessibilityLabel() {
CHECK(state_manager_);
StateProvider* state_provider = state_manager_->GetActiveStateProvider();
CHECK(state_provider);
std::optional<std::u16string> accessibility_label =
state_provider->GetAccessibilityLabel();
std::u16string name;
std::u16string description;
// The button content text as well as the button action are modified
// dynamically with very different contexts. The accessibility label is not
// always present, but when it is, it is either used as the main text (through
// name) or as the secondary text (through description) if the button content
// exists. Adapt the description to match it's default when it is not the
// accessibility label: the tooltip or no text if the button content has no
// text initially. All the values needs to be overridden every time in order
// clear the previous state effect.
std::u16string button_content(GetText());
if (accessibility_label.has_value()) {
if (button_content.empty()) {
name = accessibility_label.value();
description = state_provider->GetAvatarTooltipText();
} else {
name = button_content;
description = accessibility_label.value();
}
} else {
if (button_content.empty()) {
name = state_provider->GetAvatarTooltipText();
description = std::u16string();
} else {
name = button_content;
description = state_provider->GetAvatarTooltipText();
}
}
GetViewAccessibility().SetName(name);
GetViewAccessibility().SetDescription(description);
}
std::optional<SkColor> AvatarToolbarButton::GetHighlightTextColor() const {
CHECK(state_manager_);
StateProvider* state_provider = state_manager_->GetActiveStateProvider();
CHECK(state_provider);
const auto* const color_provider = GetColorProvider();
CHECK(color_provider);
return state_provider->GetHighlightTextColor(*color_provider);
}
std::optional<SkColor> AvatarToolbarButton::GetHighlightBorderColor() const {
const auto* const color_provider = GetColorProvider();
CHECK(color_provider);
return color_provider->GetColor(kColorToolbarButtonBorder);
}
void AvatarToolbarButton::UpdateInkdrop() {
CHECK(state_manager_);
StateProvider* state_provider = state_manager_->GetActiveStateProvider();
CHECK(state_provider);
auto [hover_color_id, ripple_color_id] = state_provider->GetInkdropColors();
ConfigureToolbarInkdropForRefresh2023(this, hover_color_id, ripple_color_id);
}
bool AvatarToolbarButton::ShouldPaintBorder() const {
if (!IsLabelPresentAndVisible()) {
return false;
}
CHECK(state_manager_);
StateProvider* state_provider = state_manager_->GetActiveStateProvider();
CHECK(state_provider);
return state_provider->ShouldPaintBorder();
}
bool AvatarToolbarButton::ShouldBlendHighlightColor() const {
return false;
}
base::ScopedClosureRunner AvatarToolbarButton::SetExplicitButtonState(
const std::u16string& text,
std::optional<std::u16string> accessibility_label,
std::optional<base::RepeatingCallback<void(bool)>> explicit_action) {
CHECK(state_manager_);
return state_manager_->SetExplicitState(text, std::move(accessibility_label),
std::move(explicit_action));
}
bool AvatarToolbarButton::HasExplicitButtonState() const {
return state_manager_->HasExplicitButtonState();
}
void AvatarToolbarButton::SetButtonActionDisabled(bool disabled) {
button_action_disabled_ = disabled;
}
bool AvatarToolbarButton::IsButtonActionDisabled() const {
return button_action_disabled_;
}
void AvatarToolbarButton::MaybeShowProfileSwitchIPH() {
// Prevent showing the promo right when the browser was created. Wait a small
// delay for a smoother animation.
base::TimeDelta time_since_creation = base::TimeTicks::Now() - creation_time_;
if (time_since_creation < g_iph_min_delay_after_creation) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&AvatarToolbarButton::MaybeShowProfileSwitchIPH,
weak_ptr_factory_.GetWeakPtr()),
g_iph_min_delay_after_creation - time_since_creation);
return;
}
// This will show the promo only after the IPH system is properly initialized.
if (!web_app::AppBrowserController::IsWebApp(browser_)) {
BrowserUserEducationInterface::From(browser_)->MaybeShowStartupFeaturePromo(
feature_engagement::kIPHProfileSwitchFeature);
} else {
// Installable PasswordManager WebUI is the only web app that has an avatar
// toolbar button.
auto app_url = browser_->app_controller()->GetAppStartUrl();
CHECK(
content::HasWebUIScheme(app_url) &&
(app_url.GetHost() == password_manager::kChromeUIPasswordManagerHost));
BrowserUserEducationInterface::From(browser_)->MaybeShowStartupFeaturePromo(
feature_engagement::kIPHPasswordsWebAppProfileSwitchFeature);
}
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
void AvatarToolbarButton::MaybeShowSupervisedUserSignInIPH() {
if (!base::FeatureList::IsEnabled(
feature_engagement::kIPHSupervisedUserProfileSigninFeature)) {
return;
}
signin::IdentityManager* const identity_manager =
IdentityManagerFactory::GetForProfile(browser_->profile());
CHECK(identity_manager);
if (!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
return;
}
auto account_info = identity_manager->FindExtendedAccountInfoByAccountId(
identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin));
if (account_info.capabilities.is_subject_to_parental_controls() !=
signin::Tribool::kTrue) {
return;
}
if (account_info.IsEmpty()) {
return;
}
// Prevent showing the promo right when the browser was created.
// This is not just used for smoother animation, but it gives the anchor
// element enough time to become visible and display the IPH.
// TODO(crbug.com/372689164): investigate alternative rescheduling,
// using `CanShowFeaturePromo`.
base::TimeDelta time_since_creation = base::TimeTicks::Now() - creation_time_;
if (time_since_creation < g_iph_min_delay_after_creation) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&AvatarToolbarButton::MaybeShowSupervisedUserSignInIPH,
weak_ptr_factory_.GetWeakPtr()),
g_iph_min_delay_after_creation - time_since_creation);
return;
}
user_education::FeaturePromoParams params(
feature_engagement::kIPHSupervisedUserProfileSigninFeature);
params.title_params = base::UTF8ToUTF16(account_info.given_name);
BrowserUserEducationInterface::From(browser_)->MaybeShowFeaturePromo(
std::move(params));
}
void AvatarToolbarButton::MaybeShowSignInBenefitsIPH() {
if (!base::FeatureList::IsEnabled(
syncer::kReplaceSyncPromosWithSignInPromos) ||
!base::FeatureList::IsEnabled(
feature_engagement::kIPHSignInBenefitsFeature)) {
return;
}
// Prevent showing the IPH bubble right when the browser was created. Wait a
// small delay for a smoother animation.
base::TimeDelta time_since_creation = base::TimeTicks::Now() - creation_time_;
if (time_since_creation < g_iph_min_delay_after_creation) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&AvatarToolbarButton::MaybeShowSignInBenefitsIPH,
weak_ptr_factory_.GetWeakPtr()),
g_iph_min_delay_after_creation - time_since_creation);
return;
}
Profile* profile = browser_->profile();
CHECK(profile);
// The IPH only concerns signed-in, non-syncing profiles.
signin::IdentityManager* const identity_manager =
IdentityManagerFactory::GetForProfile(profile);
if (!identity_manager ||
!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin) ||
identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)) {
return;
}
PrefService* prefs = profile->GetPrefs();
CHECK(prefs);
// Users who sign in after the migration and users migrated from DICe will be
// notified with other promos communicating sign-in benefits.
if (prefs->GetBoolean(prefs::kPrimaryAccountSetAfterSigninMigration) ||
prefs->GetBoolean(kDiceMigrationMigrated)) {
return;
}
BrowserUserEducationInterface::From(browser_)->MaybeShowStartupFeaturePromo(
feature_engagement::kIPHSignInBenefitsFeature);
}
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
void AvatarToolbarButton::MaybeShowExplicitBrowserSigninPreferenceRememberedIPH(
const AccountInfo& account_info) {
user_education::FeaturePromoParams params(
feature_engagement::kIPHExplicitBrowserSigninPreferenceRememberedFeature,
account_info.gaia.ToString());
params.title_params = base::UTF8ToUTF16(account_info.given_name);
BrowserUserEducationInterface::From(browser_)->MaybeShowFeaturePromo(
std::move(params));
}
void AvatarToolbarButton::OnMouseExited(const ui::MouseEvent& event) {
observer_list_.Notify(&Observer::OnMouseExited);
ToolbarButton::OnMouseExited(event);
}
void AvatarToolbarButton::OnBlur() {
observer_list_.Notify(&Observer::OnBlur);
ToolbarButton::OnBlur();
}
void AvatarToolbarButton::OnThemeChanged() {
ToolbarButton::OnThemeChanged();
if (!state_manager_) {
return;
}
UpdateProfileThemeColors(browser_, GetColorProvider());
UpdateText();
UpdateInkdrop();
}
// static
base::AutoReset<base::TimeDelta>
AvatarToolbarButton::SetScopedIPHMinDelayAfterCreationForTesting(
base::TimeDelta delay) {
return base::AutoReset<base::TimeDelta>(&g_iph_min_delay_after_creation,
delay);
}
void AvatarToolbarButton::ButtonPressed(bool is_source_accelerator) {
if (button_action_disabled_) {
return;
}
#if !BUILDFLAG(IS_CHROMEOS)
if (BrowserUserEducationInterface::From(browser_)->IsFeaturePromoActive(
feature_engagement::kIPHPasswordsSavePrimingPromoFeature)) {
BrowserUserEducationInterface::From(browser_)
->NotifyFeaturePromoFeatureUsed(
feature_engagement::kIPHPasswordsSavePrimingPromoFeature,
FeaturePromoFeatureUsedAction::kClosePromoIfPresent);
}
#endif
// Notify observers before the action is performed to allow them to close any
// open dialogs.
observer_list_.Notify(&Observer::OnButtonPressed);
CHECK(state_manager_);
StateProvider* active_state_provider =
state_manager_->GetActiveStateProvider();
CHECK(active_state_provider);
std::optional<base::RepeatingCallback<void(bool)>> action_override =
active_state_provider->GetButtonActionOverride();
if (action_override.has_value()) {
action_override->Run(is_source_accelerator);
return;
}
// By default, show the profile menu.
browser_->GetFeatures().profile_menu_coordinator()->Show(
is_source_accelerator);
}
void AvatarToolbarButton::OnPrimaryAccountChanged(
const signin::PrimaryAccountChangeEvent& event_details) {
// Try showing the IPH for signin preference remembered.
if (event_details.GetEventTypeFor(signin::ConsentLevel::kSignin) !=
signin::PrimaryAccountChangeEvent::Type::kSet ||
event_details.GetSetPrimaryAccountAccessPoint() !=
signin_metrics::AccessPoint::kSigninChoiceRemembered) {
return;
}
GaiaId gaia_id = event_details.GetCurrentState().primary_account.gaia;
Profile* profile = browser_->profile();
CHECK(profile);
PrefService* prefs = profile->GetPrefs();
CHECK(prefs);
const SigninPrefs signin_prefs(*prefs);
std::optional<base::Time> last_signout_time =
signin_prefs.GetChromeLastSignoutTime(gaia_id);
if (last_signout_time &&
base::Time::Now() - last_signout_time.value() < base::Days(14)) {
// Less than two weeks since the last sign out event.
return;
}
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(profile);
CHECK(identity_manager);
AccountInfo account_info = identity_manager->FindExtendedAccountInfo(
event_details.GetCurrentState().primary_account);
if (!account_info.given_name.empty()) {
MaybeShowExplicitBrowserSigninPreferenceRememberedIPH(account_info);
} else {
gaia_id_for_signin_choice_remembered_ = account_info.gaia;
}
}
void AvatarToolbarButton::OnExtendedAccountInfoUpdated(
const AccountInfo& info) {
if (info.gaia == gaia_id_for_signin_choice_remembered_ &&
!info.given_name.empty()) {
gaia_id_for_signin_choice_remembered_ = GaiaId();
MaybeShowExplicitBrowserSigninPreferenceRememberedIPH(info);
}
}
void AvatarToolbarButton::AfterPropertyChange(const void* key,
int64_t old_value) {
if (key == user_education::kHasInProductHelpPromoKey) {
observer_list_.Notify(
&Observer::OnIPHPromoChanged,
GetProperty(user_education::kHasInProductHelpPromoKey));
}
ToolbarButton::AfterPropertyChange(key, old_value);
}
SkColor AvatarToolbarButton::GetForegroundColor(ButtonState state) const {
if (IsLabelPresentAndVisible()) {
return GetHighlightTextColor().value_or(GetColorProvider()->GetColor(
kColorAvatarButtonHighlightDefaultForeground));
}
return ToolbarButton::GetForegroundColor(state);
}
bool AvatarToolbarButton::IsLabelPresentAndVisible() const {
if (!label()) {
return false;
}
return label()->GetVisible() && !label()->GetText().empty();
}
void AvatarToolbarButton::UpdateLayoutInsets() {
SetLayoutInsets(::GetLayoutInsets(
IsLabelPresentAndVisible() ? AVATAR_CHIP_PADDING : TOOLBAR_BUTTON));
}
int AvatarToolbarButton::GetIconSize() const {
return ui::TouchUiController::Get()->touch_ui()
? kDefaultTouchableIconSize
: kDefaultIconSizeChromeRefresh;
}
void AvatarToolbarButton::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void AvatarToolbarButton::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
// static
base::AutoReset<std::optional<base::TimeDelta>>
AvatarToolbarButton::CreateScopedInfiniteDelayOverrideForTesting(
AvatarDelayType delay_type) {
return AvatarToolbarButtonStateManager::
CreateScopedInfiniteDelayOverrideForTesting(delay_type);
}
void AvatarToolbarButton::ClearActiveStateForTesting() {
CHECK(state_manager_);
StateProvider* state_provider = state_manager_->GetActiveStateProvider();
CHECK(state_provider);
state_provider->ClearForTesting();
}
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// static
base::AutoReset<std::optional<base::TimeDelta>> AvatarToolbarButton::
CreateScopedZeroDelayOverrideSigninPendingTextForTesting() {
return AvatarToolbarButtonStateManager::
CreateScopedZeroDelayOverrideSigninPendingTextForTesting();
}
void AvatarToolbarButton::ForceShowingPromoForTesting() {
CHECK(state_manager_);
state_manager_->ForceShowingPromoForTesting();
}
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
BEGIN_METADATA(AvatarToolbarButton)
END_METADATA