| // Copyright 2014 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/views/profiles/profile_menu_view.h" |
| |
| #include <algorithm> |
| #include <string> |
| #include <utility> |
| |
| #include "base/feature_list.h" |
| #include "base/macros.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/metrics/user_metrics.h" |
| #include "build/build_config.h" |
| #include "chrome/app/vector_icons/vector_icons.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_avatar_icon_util.h" |
| #include "chrome/browser/profiles/profiles_state.h" |
| #include "chrome/browser/signin/account_consistency_mode_manager.h" |
| #include "chrome/browser/signin/chrome_signin_client_factory.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/browser/signin/signin_error_controller_factory.h" |
| #include "chrome/browser/signin/signin_ui_util.h" |
| #include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_navigator_params.h" |
| #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" |
| #include "chrome/browser/ui/sync/sync_promo_ui.h" |
| #include "chrome/browser/ui/ui_features.h" |
| #include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h" |
| #include "chrome/browser/ui/views/chrome_layout_provider.h" |
| #include "chrome/browser/ui/views/chrome_typography.h" |
| #include "chrome/browser/ui/views/hover_button.h" |
| #include "chrome/browser/ui/views/profiles/badged_profile_photo.h" |
| #include "chrome/browser/ui/views/profiles/user_manager_view.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/chromium_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "chrome/grit/theme_resources.h" |
| #include "components/signin/core/browser/signin_error_controller.h" |
| #include "components/signin/public/base/signin_pref_names.h" |
| #include "components/signin/public/identity_manager/accounts_mutator.h" |
| #include "components/signin/public/identity_manager/primary_account_mutator.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/sync/driver/sync_service_utils.h" |
| #include "components/vector_icons/vector_icons.h" |
| #include "net/base/url_util.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/image/canvas_image_source.h" |
| #include "ui/gfx/image/image_skia_operations.h" |
| #include "ui/native_theme/native_theme.h" |
| #include "ui/views/accessibility/view_accessibility.h" |
| |
| namespace { |
| |
| // Helpers -------------------------------------------------------------------- |
| |
| constexpr float kShortcutIconToImageRatio = 9.0 / 16.0; |
| |
| // Number of times the Dice sign-in promo illustration should be shown. |
| constexpr int kDiceSigninPromoIllustrationShowCountMax = 10; |
| |
| ProfileAttributesEntry* GetProfileAttributesEntry(Profile* profile) { |
| ProfileAttributesEntry* entry; |
| CHECK(g_browser_process->profile_manager() |
| ->GetProfileAttributesStorage() |
| .GetProfileAttributesWithPath(profile->GetPath(), &entry)); |
| return entry; |
| } |
| |
| BadgedProfilePhoto::BadgeType GetProfileBadgeType(Profile* profile) { |
| if (profile->IsSupervised()) { |
| return profile->IsChild() ? BadgedProfilePhoto::BADGE_TYPE_CHILD |
| : BadgedProfilePhoto::BADGE_TYPE_SUPERVISOR; |
| } |
| // |Profile::IsSyncAllowed| is needed to check whether sync is allowed by GPO |
| // policy. |
| if (AccountConsistencyModeManager::IsDiceEnabledForProfile(profile) && |
| profile->IsSyncAllowed() && |
| IdentityManagerFactory::GetForProfile(profile)->HasPrimaryAccount()) { |
| return BadgedProfilePhoto::BADGE_TYPE_SYNC_COMPLETE; |
| } |
| return BadgedProfilePhoto::BADGE_TYPE_NONE; |
| } |
| |
| void NavigateToGoogleAccountPage(Profile* profile, const std::string& email) { |
| // Create a URL so that the account chooser is shown if the account with |
| // |email| is not signed into the web. Include a UTM parameter to signal the |
| // source of the navigation. |
| GURL google_account = net::AppendQueryParameter( |
| GURL(chrome::kGoogleAccountURL), "utm_source", "chrome-profile-chooser"); |
| |
| GURL url(chrome::kGoogleAccountChooserURL); |
| url = net::AppendQueryParameter(url, "Email", email); |
| url = net::AppendQueryParameter(url, "continue", google_account.spec()); |
| |
| NavigateParams params(profile, url, ui::PAGE_TRANSITION_LINK); |
| params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; |
| Navigate(¶ms); |
| } |
| |
| bool AreSigninCookiesClearedOnExit(Profile* profile) { |
| SigninClient* client = |
| ChromeSigninClientFactory::GetInstance()->GetForProfile(profile); |
| return client->AreSigninCookiesDeletedOnExit(); |
| } |
| |
| #if defined(GOOGLE_CHROME_BUILD) |
| // Returns the Google G icon in grey and with a padding of 2. The padding is |
| // needed to make the icon look smaller, otherwise it looks too big compared to |
| // the other icons. See crbug.com/951751 for more information. |
| gfx::ImageSkia GetGoogleIconForUserMenu(int icon_size) { |
| constexpr gfx::Insets kIconPadding = gfx::Insets(2); |
| SkColor icon_color = |
| ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor( |
| ui::NativeTheme::kColorId_DefaultIconColor); |
| // |CreateVectorIcon()| doesn't override colors specified in the .icon file, |
| // therefore the image has to be colored manually with |CreateColorMask()|. |
| gfx::ImageSkia google_icon = |
| gfx::CreateVectorIcon(kGoogleGLogoIcon, icon_size - kIconPadding.width(), |
| gfx::kPlaceholderColor); |
| gfx::ImageSkia grey_google_icon = |
| gfx::ImageSkiaOperations::CreateColorMask(google_icon, icon_color); |
| |
| return gfx::CanvasImageSource::CreatePadded(grey_google_icon, kIconPadding); |
| } |
| #endif |
| |
| } // namespace |
| |
| // ProfileMenuView --------------------------------------------------------- |
| |
| // static |
| bool ProfileMenuView::close_on_deactivate_for_testing_ = true; |
| |
| ProfileMenuView::ProfileMenuView(views::Button* anchor_button, |
| Browser* browser, |
| signin_metrics::AccessPoint access_point) |
| : ProfileMenuViewBase(anchor_button, browser), |
| access_point_(access_point), |
| dice_enabled_(AccountConsistencyModeManager::IsDiceEnabledForProfile( |
| browser->profile())) { |
| GetViewAccessibility().OverrideName(GetAccessibleWindowTitle()); |
| chrome::RecordDialogCreation(chrome::DialogIdentifier::PROFILE_CHOOSER); |
| set_close_on_deactivate(close_on_deactivate_for_testing_); |
| } |
| |
| ProfileMenuView::~ProfileMenuView() = default; |
| |
| void ProfileMenuView::BuildMenu() { |
| avatar_menu_ = std::make_unique<AvatarMenu>( |
| &g_browser_process->profile_manager()->GetProfileAttributesStorage(), |
| this, browser()); |
| avatar_menu_->RebuildMenu(); |
| |
| if (!base::FeatureList::IsEnabled(features::kProfileMenuRevamp)) { |
| if (dice_enabled_) { |
| // Fetch DICE accounts. Note: This always includes the primary account if |
| // it is set. |
| dice_accounts_ = |
| signin_ui_util::GetAccountsForDicePromos(browser()->profile()); |
| } |
| AddProfileMenuView(avatar_menu_.get()); |
| return; |
| } |
| |
| Profile* profile = browser()->profile(); |
| if (profile->IsRegularProfile()) { |
| BuildIdentity(); |
| BuildSyncInfo(); |
| BuildAccountFeatureButtons(); |
| BuildAutofillButtons(); |
| } else if (profile->IsIncognitoProfile()) { |
| BuildIncognitoIdentity(); |
| } else if (profile->IsGuestSession()) { |
| BuildGuestIdentity(); |
| } else { |
| NOTREACHED(); |
| } |
| |
| BuildProfileHeading(); |
| BuildSelectableProfiles(); |
| BuildProfileFeatureButtons(); |
| } |
| |
| void ProfileMenuView::OnAvatarMenuChanged( |
| AvatarMenu* avatar_menu) { |
| // TODO(crbug.com/993752): Remove AvatarMenu observer. |
| } |
| |
| void ProfileMenuView::FocusButtonOnKeyboardOpen() { |
| if (first_profile_button_) |
| first_profile_button_->RequestFocus(); |
| } |
| |
| void ProfileMenuView::OnWidgetClosing(views::Widget* /*widget*/) { |
| // Unsubscribe from everything early so that the updates do not reach the |
| // bubble and change its state. |
| avatar_menu_.reset(); |
| } |
| |
| base::string16 ProfileMenuView::GetAccessibleWindowTitle() const { |
| return l10n_util::GetStringUTF16( |
| IDS_PROFILES_PROFILE_BUBBLE_ACCESSIBLE_TITLE); |
| } |
| |
| void ProfileMenuView::OnManageGoogleAccountButtonClicked() { |
| RecordClick(ActionableItem::kManageGoogleAccountButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction( |
| base::UserMetricsAction("ProfileChooser_ManageGoogleAccountClicked")); |
| |
| Profile* profile = browser()->profile(); |
| signin::IdentityManager* identity_manager = |
| IdentityManagerFactory::GetForProfile(profile); |
| DCHECK(identity_manager->HasUnconsentedPrimaryAccount()); |
| |
| NavigateToGoogleAccountPage( |
| profile, identity_manager->GetUnconsentedPrimaryAccountInfo().email); |
| } |
| |
| void ProfileMenuView::OnPasswordsButtonClicked() { |
| RecordClick(ActionableItem::kPasswordsButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction( |
| base::UserMetricsAction("ProfileChooser_PasswordsClicked")); |
| NavigateToManagePasswordsPage( |
| browser(), password_manager::ManagePasswordsReferrer::kProfileChooser); |
| } |
| |
| void ProfileMenuView::OnCreditCardsButtonClicked() { |
| RecordClick(ActionableItem::kCreditCardsButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction(base::UserMetricsAction("ProfileChooser_PaymentsClicked")); |
| chrome::ShowSettingsSubPage(browser(), chrome::kPaymentsSubPage); |
| } |
| |
| void ProfileMenuView::OnAddressesButtonClicked() { |
| RecordClick(ActionableItem::kAddressesButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction( |
| base::UserMetricsAction("ProfileChooser_AddressesClicked")); |
| chrome::ShowSettingsSubPage(browser(), chrome::kAddressesSubPage); |
| } |
| |
| void ProfileMenuView::OnGuestProfileButtonClicked() { |
| RecordClick(ActionableItem::kGuestProfileButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction(base::UserMetricsAction("ProfileChooser_GuestClicked")); |
| PrefService* service = g_browser_process->local_state(); |
| DCHECK(service); |
| DCHECK(service->GetBoolean(prefs::kBrowserGuestModeEnabled)); |
| profiles::SwitchToGuestProfile(ProfileManager::CreateCallback()); |
| } |
| |
| void ProfileMenuView::OnManageProfilesButtonClicked() { |
| RecordClick(ActionableItem::kManageProfilesButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction(base::UserMetricsAction("ProfileChooser_ManageClicked")); |
| UserManager::Show(base::FilePath(), |
| profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); |
| PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER); |
| } |
| |
| void ProfileMenuView::OnLockButtonClicked() { |
| RecordClick(ActionableItem::kLockButton); |
| profiles::LockProfile(browser()->profile()); |
| // TODO(crbug.com/995757): Remove. |
| PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK); |
| } |
| |
| void ProfileMenuView::OnExitProfileButtonClicked() { |
| RecordClick(ActionableItem::kExitProfileButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction(base::UserMetricsAction("ProfileChooser_CloseAllClicked")); |
| profiles::CloseProfileWindows(browser()->profile()); |
| } |
| |
| void ProfileMenuView::OnSyncSettingsButtonClicked() { |
| RecordClick(ActionableItem::kSyncSettingsButton); |
| chrome::ShowSettingsSubPage(browser(), chrome::kSyncSetupSubPage); |
| } |
| |
| void ProfileMenuView::OnSyncErrorButtonClicked( |
| sync_ui_util::AvatarSyncErrorType error) { |
| RecordClick(ActionableItem::kSyncErrorButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction( |
| base::UserMetricsAction("ProfileChooser_SignInAgainClicked")); |
| switch (error) { |
| case sync_ui_util::MANAGED_USER_UNRECOVERABLE_ERROR: |
| chrome::ShowSettingsSubPage(browser(), chrome::kSignOutSubPage); |
| break; |
| case sync_ui_util::UNRECOVERABLE_ERROR: |
| if (ProfileSyncServiceFactory::GetForProfile(browser()->profile())) { |
| syncer::RecordSyncEvent(syncer::STOP_FROM_OPTIONS); |
| } |
| |
| // GetPrimaryAccountMutator() might return nullptr on some platforms. |
| if (auto* account_mutator = |
| IdentityManagerFactory::GetForProfile(browser()->profile()) |
| ->GetPrimaryAccountMutator()) { |
| account_mutator->ClearPrimaryAccount( |
| signin::PrimaryAccountMutator::ClearAccountsAction::kDefault, |
| signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, |
| signin_metrics::SignoutDelete::IGNORE_METRIC); |
| Hide(); |
| browser()->signin_view_controller()->ShowSignin( |
| profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_); |
| } |
| break; |
| case sync_ui_util::AUTH_ERROR: |
| Hide(); |
| browser()->signin_view_controller()->ShowSignin( |
| profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, browser(), access_point_); |
| break; |
| case sync_ui_util::UPGRADE_CLIENT_ERROR: |
| chrome::OpenUpdateChromeDialog(browser()); |
| break; |
| case sync_ui_util::PASSPHRASE_ERROR: |
| case sync_ui_util::SETTINGS_UNCONFIRMED_ERROR: |
| chrome::ShowSettingsSubPage(browser(), chrome::kSyncSetupSubPage); |
| break; |
| case sync_ui_util::NO_SYNC_ERROR: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void ProfileMenuView::OnCurrentProfileCardClicked() { |
| RecordClick(ActionableItem::kCurrentProfileCard); |
| if (dice_enabled_ && |
| IdentityManagerFactory::GetForProfile(browser()->profile()) |
| ->HasPrimaryAccount()) { |
| chrome::ShowSettingsSubPage(browser(), chrome::kPeopleSubPage); |
| } else { |
| // Open settings to edit profile name and image. The profile doesn't need |
| // to be authenticated to open this. |
| avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex()); |
| PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE); |
| PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME); |
| } |
| } |
| |
| void ProfileMenuView::OnSigninButtonClicked() { |
| RecordClick(ActionableItem::kSigninButton); |
| Hide(); |
| browser()->signin_view_controller()->ShowSignin( |
| profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_); |
| } |
| |
| void ProfileMenuView::OnSigninAccountButtonClicked(AccountInfo account) { |
| RecordClick(ActionableItem::kSigninAccountButton); |
| Hide(); |
| signin_ui_util::EnableSyncFromPromo(browser(), account, access_point_, |
| true /* is_default_promo_account */); |
| } |
| |
| void ProfileMenuView::OnSignoutButtonClicked() { |
| RecordClick(ActionableItem::kSignoutButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction(base::UserMetricsAction("Signin_Signout_FromUserMenu")); |
| Hide(); |
| // Sign out from all accounts. |
| IdentityManagerFactory::GetForProfile(browser()->profile()) |
| ->GetAccountsMutator() |
| ->RemoveAllAccounts(signin_metrics::SourceForRefreshTokenOperation:: |
| kUserMenu_SignOutAllAccounts); |
| } |
| |
| void ProfileMenuView::OnOtherProfileSelected( |
| const base::FilePath& profile_path) { |
| RecordClick(ActionableItem::kOtherProfileButton); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction(base::UserMetricsAction("ProfileChooser_ProfileClicked")); |
| Hide(); |
| profiles::SwitchToProfile(profile_path, /*always_create=*/false, |
| ProfileManager::CreateCallback(), |
| ProfileMetrics::SWITCH_PROFILE_ICON); |
| } |
| |
| void ProfileMenuView::OnCookiesClearedOnExitLinkClicked() { |
| RecordClick(ActionableItem::kCookiesClearedOnExitLink); |
| // TODO(crbug.com/995757): Remove user action. |
| base::RecordAction( |
| base::UserMetricsAction("ProfileChooser_CookieSettingsClicked")); |
| chrome::ShowSettingsSubPage(browser(), chrome::kContentSettingsSubPage + |
| std::string("/") + |
| chrome::kCookieSettingsSubPage); |
| } |
| |
| void ProfileMenuView::OnAddNewProfileButtonClicked() { |
| RecordClick(ActionableItem::kAddNewProfileButton); |
| UserManager::Show(/*profile_path_to_focus=*/base::FilePath(), |
| profiles::USER_MANAGER_OPEN_CREATE_USER_PAGE); |
| } |
| |
| void ProfileMenuView::RecordClick(ActionableItem item) { |
| base::UmaHistogramEnumeration("Profile.Menu.ClickedActionableItem", item); |
| } |
| |
| void ProfileMenuView::BuildIdentity() { |
| Profile* profile = browser()->profile(); |
| signin::IdentityManager* identity_manager = |
| IdentityManagerFactory::GetForProfile(profile); |
| CoreAccountInfo account = |
| identity_manager->GetUnconsentedPrimaryAccountInfo(); |
| base::Optional<AccountInfo> account_info = |
| identity_manager->FindExtendedAccountInfoForAccountWithRefreshToken( |
| account); |
| |
| if (account_info.has_value()) { |
| SetIdentityInfo(account_info.value().account_image.AsImageSkia(), |
| GetSyncIcon(), |
| base::UTF8ToUTF16(account_info.value().full_name), |
| base::UTF8ToUTF16(account_info.value().email)); |
| } else { |
| ProfileAttributesEntry* profile_attributes = |
| GetProfileAttributesEntry(profile); |
| SetIdentityInfo( |
| profile_attributes->GetAvatarIcon().AsImageSkia(), GetSyncIcon(), |
| profile_attributes->GetName(), |
| l10n_util::GetStringUTF16(IDS_PROFILES_LOCAL_PROFILE_STATE)); |
| } |
| } |
| |
| void ProfileMenuView::BuildGuestIdentity() { |
| SetIdentityInfo(profiles::GetGuestAvatar(), GetSyncIcon(), |
| l10n_util::GetStringUTF16(IDS_GUEST_PROFILE_NAME)); |
| } |
| |
| void ProfileMenuView::BuildIncognitoIdentity() { |
| int incognito_window_count = |
| BrowserList::GetIncognitoSessionsActiveForProfile(browser()->profile()); |
| |
| SetIdentityInfo( |
| ImageForMenu(kIncognitoProfileIcon), GetSyncIcon(), |
| l10n_util::GetStringUTF16(IDS_INCOGNITO_PROFILE_MENU_TITLE), |
| incognito_window_count > 1 |
| ? l10n_util::GetPluralStringFUTF16(IDS_INCOGNITO_WINDOW_COUNT_MESSAGE, |
| incognito_window_count) |
| : base::string16()); |
| } |
| |
| gfx::ImageSkia ProfileMenuView::GetSyncIcon() { |
| Profile* profile = browser()->profile(); |
| signin::IdentityManager* identity_manager = |
| IdentityManagerFactory::GetForProfile(profile); |
| ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); |
| |
| if (!profile->IsRegularProfile()) |
| return gfx::ImageSkia(); |
| |
| if (!identity_manager->HasPrimaryAccount()) |
| return ColoredImageForMenu(kSyncPausedCircleIcon, gfx::kGoogleGrey400); |
| |
| const gfx::VectorIcon* icon = nullptr; |
| ui::NativeTheme::ColorId color_id; |
| int unused; |
| switch ( |
| sync_ui_util::GetMessagesForAvatarSyncError(profile, &unused, &unused)) { |
| case sync_ui_util::NO_SYNC_ERROR: |
| icon = &kSyncCircleIcon; |
| color_id = ui::NativeTheme::kColorId_AlertSeverityLow; |
| break; |
| case sync_ui_util::AUTH_ERROR: |
| icon = &kSyncPausedCircleIcon; |
| color_id = ui::NativeTheme::kColorId_ProminentButtonColor; |
| break; |
| case sync_ui_util::MANAGED_USER_UNRECOVERABLE_ERROR: |
| case sync_ui_util::UNRECOVERABLE_ERROR: |
| case sync_ui_util::UPGRADE_CLIENT_ERROR: |
| case sync_ui_util::PASSPHRASE_ERROR: |
| case sync_ui_util::SETTINGS_UNCONFIRMED_ERROR: |
| icon = &kSyncPausedCircleIcon; |
| color_id = ui::NativeTheme::kColorId_AlertSeverityHigh; |
| break; |
| } |
| return ColoredImageForMenu(*icon, native_theme->GetSystemColor(color_id)); |
| } |
| |
| void ProfileMenuView::BuildAutofillButtons() { |
| AddShortcutFeatureButton( |
| ImageForMenu(kKeyIcon, kShortcutIconToImageRatio), |
| l10n_util::GetStringUTF16(IDS_PROFILES_PASSWORDS_LINK), |
| base::BindRepeating(&ProfileMenuView::OnPasswordsButtonClicked, |
| base::Unretained(this))); |
| |
| AddShortcutFeatureButton( |
| ImageForMenu(kCreditCardIcon, kShortcutIconToImageRatio), |
| l10n_util::GetStringUTF16(IDS_PROFILES_CREDIT_CARDS_LINK), |
| base::BindRepeating(&ProfileMenuView::OnCreditCardsButtonClicked, |
| base::Unretained(this))); |
| |
| AddShortcutFeatureButton( |
| ImageForMenu(vector_icons::kLocationOnIcon, kShortcutIconToImageRatio), |
| l10n_util::GetStringUTF16(IDS_PROFILES_ADDRESSES_LINK), |
| base::BindRepeating(&ProfileMenuView::OnAddressesButtonClicked, |
| base::Unretained(this))); |
| } |
| |
| void ProfileMenuView::BuildSyncInfo() { |
| signin::IdentityManager* identity_manager = |
| IdentityManagerFactory::GetForProfile(browser()->profile()); |
| |
| if (identity_manager->HasPrimaryAccount()) { |
| // Show sync state. |
| int description_string_id, button_string_id; |
| sync_ui_util::AvatarSyncErrorType error = |
| sync_ui_util::GetMessagesForAvatarSyncError( |
| browser()->profile(), &description_string_id, &button_string_id); |
| |
| if (error == sync_ui_util::NO_SYNC_ERROR) { |
| SetSyncInfo( |
| GetSyncIcon(), |
| /*description=*/base::string16(), |
| l10n_util::GetStringUTF16(IDS_PROFILES_OPEN_SYNC_SETTINGS_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnSyncSettingsButtonClicked, |
| base::Unretained(this))); |
| } else { |
| // Overwrite error description with short version for the menu. |
| description_string_id = (error == sync_ui_util::AUTH_ERROR) |
| ? IDS_PROFILES_DICE_SYNC_PAUSED_TITLE |
| : IDS_SYNC_ERROR_USER_MENU_TITLE; |
| |
| SetSyncInfo( |
| GetSyncIcon(), l10n_util::GetStringUTF16(description_string_id), |
| l10n_util::GetStringUTF16(button_string_id), |
| base::BindRepeating(&ProfileMenuView::OnSyncErrorButtonClicked, |
| base::Unretained(this), error)); |
| } |
| return; |
| } |
| |
| // Show sync promos. |
| CoreAccountInfo unconsented_account = |
| identity_manager->GetUnconsentedPrimaryAccountInfo(); |
| base::Optional<AccountInfo> account_info = |
| identity_manager->FindExtendedAccountInfoForAccountWithRefreshToken( |
| unconsented_account); |
| |
| if (account_info.has_value()) { |
| SetSyncInfo( |
| GetSyncIcon(), |
| l10n_util::GetStringUTF16(IDS_PROFILES_DICE_NOT_SYNCING_TITLE), |
| l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SIGNIN_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnSigninAccountButtonClicked, |
| base::Unretained(this), account_info.value())); |
| } else { |
| SetSyncInfo(/*icon=*/gfx::ImageSkia(), |
| l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SYNC_PROMO), |
| l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SIGNIN_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnSigninButtonClicked, |
| base::Unretained(this))); |
| } |
| } |
| |
| void ProfileMenuView::BuildAccountFeatureButtons() { |
| signin::IdentityManager* identity_manager = |
| IdentityManagerFactory::GetForProfile(browser()->profile()); |
| if (!identity_manager->HasUnconsentedPrimaryAccount()) |
| return; |
| |
| AddAccountFeatureButton( |
| #if defined(GOOGLE_CHROME_BUILD) |
| // The Google G icon needs to be shrunk, so it won't look too big |
| // compared to the other icons. |
| ImageForMenu(kGoogleGLogoIcon, /*icon_to_image_ratio=*/0.75), |
| #else |
| gfx::ImageSkia(), |
| #endif |
| l10n_util::GetStringUTF16(IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT), |
| base::BindRepeating(&ProfileMenuView::OnManageGoogleAccountButtonClicked, |
| base::Unretained(this))); |
| |
| if (!identity_manager->HasPrimaryAccount()) { |
| // The sign-out button is only shown when sync is off. |
| AddAccountFeatureButton( |
| ImageForMenu(kSignOutIcon), |
| l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT), |
| base::BindRepeating(&ProfileMenuView::OnSignoutButtonClicked, |
| base::Unretained(this))); |
| } |
| } |
| |
| void ProfileMenuView::BuildProfileHeading() { |
| SetProfileHeading( |
| l10n_util::GetStringUTF16(IDS_PROFILES_OTHER_PROFILES_TITLE)); |
| } |
| |
| void ProfileMenuView::BuildSelectableProfiles() { |
| auto profile_entries = g_browser_process->profile_manager() |
| ->GetProfileAttributesStorage() |
| .GetAllProfilesAttributes(); |
| for (ProfileAttributesEntry* profile_entry : profile_entries) { |
| // The current profile is excluded. |
| if (profile_entry->GetPath() == browser()->profile()->GetPath()) |
| continue; |
| |
| AddSelectableProfile( |
| profile_entry->GetAvatarIcon().AsImageSkia(), profile_entry->GetName(), |
| base::BindRepeating(&ProfileMenuView::OnOtherProfileSelected, |
| base::Unretained(this), profile_entry->GetPath())); |
| } |
| |
| if (!browser()->profile()->IsGuestSession()) { |
| AddSelectableProfile( |
| profiles::GetGuestAvatar(), |
| l10n_util::GetStringUTF16(IDS_GUEST_PROFILE_NAME), |
| base::BindRepeating(&ProfileMenuView::OnGuestProfileButtonClicked, |
| base::Unretained(this))); |
| } |
| } |
| |
| void ProfileMenuView::BuildProfileFeatureButtons() { |
| AddProfileShortcutFeatureButton( |
| ImageForMenu(vector_icons::kSettingsIcon, kShortcutIconToImageRatio), |
| l10n_util::GetStringUTF16(IDS_PROFILES_MANAGE_USERS_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnManageProfilesButtonClicked, |
| base::Unretained(this))); |
| |
| AddProfileFeatureButton( |
| ImageForMenu(kAddIcon, /*icon_to_image_ratio=*/0.75), |
| l10n_util::GetStringUTF16(IDS_ADD), |
| base::BindRepeating(&ProfileMenuView::OnAddNewProfileButtonClicked, |
| base::Unretained(this))); |
| } |
| |
| void ProfileMenuView::AddProfileMenuView(AvatarMenu* avatar_menu) { |
| // Separate items into active and alternatives. |
| const AvatarMenu::Item* active_item = nullptr; |
| for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) { |
| if (avatar_menu->GetItemAt(i).active) { |
| active_item = &avatar_menu->GetItemAt(i); |
| break; |
| } |
| } |
| |
| bool sync_error = |
| active_item ? AddSyncErrorViewIfNeeded(*active_item) : false; |
| |
| if (!sync_error || !dice_enabled_) { |
| // Guest windows don't have an active profile. |
| if (active_item) |
| AddCurrentProfileView(*active_item, /* is_guest = */ false); |
| else |
| AddGuestProfileView(); |
| } |
| |
| #if defined(GOOGLE_CHROME_BUILD) |
| if (dice_enabled_ && !dice_accounts_.empty() && |
| !SigninErrorControllerFactory::GetForProfile(browser()->profile()) |
| ->HasError()) { |
| AddManageGoogleAccountButton(); |
| } |
| #endif |
| |
| if (browser()->profile()->IsSupervised()) |
| AddSupervisedUserDisclaimerView(); |
| |
| if (active_item) |
| AddAutofillHomeView(); |
| |
| const bool display_lock = active_item && active_item->signed_in && |
| profiles::IsLockAvailable(browser()->profile()); |
| AddOptionsView(display_lock, avatar_menu); |
| } |
| |
| bool ProfileMenuView::AddSyncErrorViewIfNeeded( |
| const AvatarMenu::Item& avatar_item) { |
| int content_string_id, button_string_id; |
| sync_ui_util::AvatarSyncErrorType error = |
| sync_ui_util::GetMessagesForAvatarSyncError( |
| browser()->profile(), &content_string_id, &button_string_id); |
| if (error == sync_ui_util::NO_SYNC_ERROR) |
| return false; |
| |
| if (dice_enabled_) { |
| AddDiceSyncErrorView(avatar_item, error, button_string_id); |
| } else { |
| AddPreDiceSyncErrorView(avatar_item, error, button_string_id, |
| content_string_id); |
| } |
| |
| return true; |
| } |
| |
| void ProfileMenuView::AddPreDiceSyncErrorView( |
| const AvatarMenu::Item& avatar_item, |
| sync_ui_util::AvatarSyncErrorType error, |
| int button_string_id, |
| int content_string_id) { |
| AddMenuGroup(); |
| auto sync_problem_icon = std::make_unique<views::ImageView>(); |
| sync_problem_icon->SetImage( |
| gfx::CreateVectorIcon(kSyncProblemIcon, BadgedProfilePhoto::kImageSize, |
| GetNativeTheme()->GetSystemColor( |
| ui::NativeTheme::kColorId_AlertSeverityHigh))); |
| views::Button* button = CreateAndAddTitleCard( |
| std::move(sync_problem_icon), |
| l10n_util::GetStringUTF16(IDS_SYNC_ERROR_USER_MENU_TITLE), |
| l10n_util::GetStringUTF16(content_string_id), base::RepeatingClosure()); |
| static_cast<HoverButton*>(button)->SetStyle(HoverButton::STYLE_ERROR); |
| |
| // Adds an action button if an action exists. |
| if (button_string_id) { |
| CreateAndAddBlueButton( |
| l10n_util::GetStringUTF16(button_string_id), true /* md_style */, |
| base::BindRepeating(&ProfileMenuView::OnSyncErrorButtonClicked, |
| base::Unretained(this), error)); |
| } |
| } |
| |
| void ProfileMenuView::AddDiceSyncErrorView( |
| const AvatarMenu::Item& avatar_item, |
| sync_ui_util::AvatarSyncErrorType error, |
| int button_string_id) { |
| // Creates a view containing an error hover button displaying the current |
| // profile (only selectable when sync is paused or disabled) and when sync is |
| // not disabled there is a blue button to resolve the error. |
| const bool show_sync_paused_ui = error == sync_ui_util::AUTH_ERROR; |
| const bool sync_disabled = !browser()->profile()->IsSyncAllowed(); |
| |
| AddMenuGroup(); |
| |
| if (show_sync_paused_ui && |
| base::FeatureList::IsEnabled( |
| features::kShowSyncPausedReasonCookiesClearedOnExit) && |
| AreSigninCookiesClearedOnExit(browser()->profile())) { |
| AddSyncPausedReasonCookiesClearedOnExit(); |
| } |
| // Add profile card. |
| auto current_profile_photo = std::make_unique<BadgedProfilePhoto>( |
| show_sync_paused_ui |
| ? BadgedProfilePhoto::BADGE_TYPE_SYNC_PAUSED |
| : sync_disabled ? BadgedProfilePhoto::BADGE_TYPE_SYNC_DISABLED |
| : BadgedProfilePhoto::BADGE_TYPE_SYNC_ERROR, |
| avatar_item.icon); |
| views::Button* current_profile_card = CreateAndAddTitleCard( |
| std::move(current_profile_photo), |
| l10n_util::GetStringUTF16( |
| show_sync_paused_ui |
| ? IDS_PROFILES_DICE_SYNC_PAUSED_TITLE |
| : sync_disabled ? IDS_PROFILES_DICE_SYNC_DISABLED_TITLE |
| : IDS_SYNC_ERROR_USER_MENU_TITLE), |
| avatar_item.username, |
| base::BindRepeating(&ProfileMenuView::OnCurrentProfileCardClicked, |
| base::Unretained(this))); |
| |
| if (!show_sync_paused_ui && !sync_disabled) { |
| static_cast<HoverButton*>(current_profile_card) |
| ->SetStyle(HoverButton::STYLE_ERROR); |
| current_profile_card->SetEnabled(false); |
| } |
| |
| if (!sync_disabled) { |
| CreateAndAddBlueButton( |
| l10n_util::GetStringUTF16(button_string_id), true /* md_style */, |
| base::BindRepeating(&ProfileMenuView::OnSyncErrorButtonClicked, |
| base::Unretained(this), error)); |
| base::RecordAction( |
| base::UserMetricsAction("ProfileChooser_SignInAgainDisplayed")); |
| } |
| } |
| |
| void ProfileMenuView::AddSyncPausedReasonCookiesClearedOnExit() { |
| base::string16 link_text = l10n_util::GetStringUTF16( |
| IDS_SYNC_PAUSED_REASON_CLEAR_COOKIES_ON_EXIT_LINK_TEXT); |
| size_t link_begin = 0; |
| base::string16 text = l10n_util::GetStringFUTF16( |
| IDS_SYNC_PAUSED_REASON_CLEAR_COOKIES_ON_EXIT, link_text, &link_begin); |
| |
| CreateAndAddLabelWithLink( |
| text, gfx::Range(link_begin, link_begin + link_text.length()), |
| base::BindRepeating(&ProfileMenuView::OnCookiesClearedOnExitLinkClicked, |
| base::Unretained(this))); |
| } |
| |
| void ProfileMenuView::AddCurrentProfileView( |
| const AvatarMenu::Item& avatar_item, |
| bool is_guest) { |
| Profile* profile = browser()->profile(); |
| const bool sync_disabled = !profile->IsSyncAllowed(); |
| if (!is_guest && sync_disabled) { |
| AddDiceSyncErrorView(avatar_item, sync_ui_util::NO_SYNC_ERROR, 0); |
| return; |
| } |
| |
| if (!avatar_item.signed_in && dice_enabled_ && |
| SyncPromoUI::ShouldShowSyncPromo(profile)) { |
| AddDiceSigninView(); |
| return; |
| } |
| |
| AddMenuGroup(); |
| |
| auto current_profile_photo = std::make_unique<BadgedProfilePhoto>( |
| GetProfileBadgeType(profile), avatar_item.icon); |
| const base::string16 profile_name = |
| profiles::GetAvatarNameForProfile(profile->GetPath()); |
| |
| // Show the profile name by itself if not signed in or account consistency is |
| // disabled. Otherwise, show the email attached to the profile. |
| bool show_email = !is_guest && avatar_item.signed_in; |
| const base::string16 hover_button_title = |
| dice_enabled_ && profile->IsSyncAllowed() && show_email |
| ? l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_COMPLETE_TITLE) |
| : profile_name; |
| |
| views::Button* current_profile_card = CreateAndAddTitleCard( |
| std::move(current_profile_photo), hover_button_title, |
| show_email ? avatar_item.username : base::string16(), |
| base::BindRepeating(&ProfileMenuView::OnCurrentProfileCardClicked, |
| base::Unretained(this))); |
| // TODO(crbug.com/815047): Sometimes, |avatar_item.username| is empty when |
| // |show_email| is true, which should never happen. This causes a crash when |
| // setting the elision behavior, so until this bug is fixed, avoid the crash |
| // by checking that the username is not empty. |
| if (show_email && !avatar_item.username.empty()) |
| static_cast<HoverButton*>(current_profile_card) |
| ->SetSubtitleElideBehavior(gfx::ELIDE_EMAIL); |
| |
| // The available links depend on the type of profile that is active. |
| if (is_guest) { |
| current_profile_card->SetEnabled(false); |
| } else if (avatar_item.signed_in) { |
| current_profile_card->SetAccessibleName(l10n_util::GetStringFUTF16( |
| IDS_PROFILES_EDIT_SIGNED_IN_PROFILE_ACCESSIBLE_NAME, profile_name, |
| avatar_item.username)); |
| } else { |
| bool is_signin_allowed = |
| profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed); |
| // For the dice promo equivalent, see AddDiceSigninPromo() call sites. |
| if (!dice_enabled_ && is_signin_allowed) |
| AddPreDiceSigninPromo(); |
| |
| current_profile_card->SetAccessibleName(l10n_util::GetStringFUTF16( |
| IDS_PROFILES_EDIT_PROFILE_ACCESSIBLE_NAME, profile_name)); |
| } |
| } |
| |
| void ProfileMenuView::AddPreDiceSigninPromo() { |
| AddMenuGroup(false /* add_separator */); |
| CreateAndAddLabel(l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO)); |
| |
| CreateAndAddBlueButton( |
| l10n_util::GetStringFUTF16( |
| IDS_SYNC_START_SYNC_BUTTON_LABEL, |
| l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)), |
| true /* md_style */, |
| base::BindRepeating(&ProfileMenuView::OnSigninButtonClicked, |
| base::Unretained(this))); |
| |
| signin_metrics::RecordSigninImpressionUserActionForAccessPoint( |
| signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN); |
| } |
| |
| void ProfileMenuView::AddDiceSigninPromo() { |
| AddMenuGroup(); |
| |
| // Show promo illustration + text when there is no promo account. |
| if (GetDiceSigninPromoShowCount() <= |
| kDiceSigninPromoIllustrationShowCountMax) { |
| // Add the illustration. |
| ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| std::unique_ptr<NonAccessibleImageView> illustration = |
| std::make_unique<NonAccessibleImageView>(); |
| illustration->SetImage( |
| *rb.GetNativeImageNamed(IDR_PROFILES_DICE_TURN_ON_SYNC).ToImageSkia()); |
| AddViewItem(std::move(illustration)); |
| } |
| // Add the promo text. |
| CreateAndAddLabel(l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SYNC_PROMO)); |
| |
| // Create a sign-in button without account information. |
| CreateAndAddDiceSigninButton( |
| /*account_info=*/nullptr, /*account_icon=*/nullptr, |
| base::BindRepeating(&ProfileMenuView::OnSigninButtonClicked, |
| base::Unretained(this))); |
| } |
| |
| void ProfileMenuView::AddDiceSigninView() { |
| IncrementDiceSigninPromoShowCount(); |
| // Create a view that holds an illustration, a promo text and a button to turn |
| // on Sync. The promo illustration is only shown the first 10 times per |
| // profile. |
| const bool promo_account_available = !dice_accounts_.empty(); |
| |
| // Log sign-in impressions user metrics. |
| signin_metrics::RecordSigninImpressionUserActionForAccessPoint( |
| signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN); |
| signin_metrics::RecordSigninImpressionWithAccountUserActionForAccessPoint( |
| signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN, |
| promo_account_available); |
| |
| if (!promo_account_available) { |
| // For the pre-dice promo equivalent, see AddPreDiceSigninPromo() call |
| // sites. |
| AddDiceSigninPromo(); |
| return; |
| } |
| |
| AddMenuGroup(); |
| // Create a button to sign in the first account of |dice_accounts_|. |
| AccountInfo dice_promo_default_account = dice_accounts_[0]; |
| gfx::Image account_icon = dice_promo_default_account.account_image; |
| if (account_icon.IsEmpty()) { |
| account_icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| profiles::GetPlaceholderAvatarIconResourceID()); |
| } |
| CreateAndAddDiceSigninButton( |
| &dice_promo_default_account, &account_icon, |
| base::BindRepeating(&ProfileMenuView::OnSigninAccountButtonClicked, |
| base::Unretained(this), dice_promo_default_account)); |
| |
| // Add sign out button. |
| CreateAndAddBlueButton( |
| l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT), false /* md_style */, |
| base::BindRepeating(&ProfileMenuView::OnSignoutButtonClicked, |
| base::Unretained(this))); |
| } |
| |
| void ProfileMenuView::AddGuestProfileView() { |
| gfx::Image guest_icon = |
| ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| profiles::GetPlaceholderAvatarIconResourceID()); |
| AvatarMenu::Item guest_avatar_item(0, base::FilePath(), guest_icon); |
| guest_avatar_item.active = true; |
| guest_avatar_item.name = l10n_util::GetStringUTF16( |
| IDS_PROFILES_GUEST_PROFILE_NAME); |
| guest_avatar_item.signed_in = false; |
| |
| AddCurrentProfileView(guest_avatar_item, true); |
| } |
| |
| void ProfileMenuView::AddOptionsView(bool display_lock, |
| AvatarMenu* avatar_menu) { |
| AddMenuGroup(); |
| |
| const bool is_guest = browser()->profile()->IsGuestSession(); |
| // Add the user switching buttons. |
| // Order them such that the active user profile comes first (for Dice). |
| std::vector<size_t> ordered_item_indices; |
| for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) { |
| if (avatar_menu->GetItemAt(i).active) |
| ordered_item_indices.insert(ordered_item_indices.begin(), i); |
| else |
| ordered_item_indices.push_back(i); |
| } |
| for (size_t profile_index : ordered_item_indices) { |
| const AvatarMenu::Item& item = avatar_menu->GetItemAt(profile_index); |
| if (!item.active) { |
| gfx::Image image = profiles::GetSizedAvatarIcon( |
| item.icon, true, GetDefaultIconSize(), GetDefaultIconSize(), |
| profiles::SHAPE_CIRCLE); |
| views::Button* button = CreateAndAddButton( |
| *image.ToImageSkia(), profiles::GetProfileSwitcherTextForItem(item), |
| base::BindRepeating(&ProfileMenuView::OnOtherProfileSelected, |
| base::Unretained(this), item.profile_path)); |
| |
| if (!first_profile_button_) |
| first_profile_button_ = button; |
| } |
| } |
| |
| UMA_HISTOGRAM_BOOLEAN("ProfileChooser.HasProfilesShown", |
| first_profile_button_); |
| |
| // Add the "Guest" button for browsing as guest |
| if (!is_guest && !browser()->profile()->IsSupervised()) { |
| PrefService* service = g_browser_process->local_state(); |
| DCHECK(service); |
| if (service->GetBoolean(prefs::kBrowserGuestModeEnabled)) { |
| CreateAndAddButton( |
| CreateVectorIcon(kUserMenuGuestIcon), |
| l10n_util::GetStringUTF16(IDS_PROFILES_OPEN_GUEST_PROFILE_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnGuestProfileButtonClicked, |
| base::Unretained(this))); |
| } |
| } |
| |
| if (is_guest) { |
| CreateAndAddButton( |
| CreateVectorIcon(kCloseAllIcon), |
| l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST), |
| base::BindRepeating(&ProfileMenuView::OnExitProfileButtonClicked, |
| base::Unretained(this))); |
| } else { |
| CreateAndAddButton( |
| CreateVectorIcon(vector_icons::kSettingsIcon), |
| l10n_util::GetStringUTF16(IDS_PROFILES_MANAGE_USERS_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnManageProfilesButtonClicked, |
| base::Unretained(this))); |
| } |
| |
| if (display_lock) { |
| lock_button_ = CreateAndAddButton( |
| gfx::CreateVectorIcon(vector_icons::kLockIcon, GetDefaultIconSize(), |
| gfx::kChromeIconGrey), |
| l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnLockButtonClicked, |
| base::Unretained(this))); |
| } else if (!is_guest) { |
| AvatarMenu::Item active_avatar_item = |
| avatar_menu->GetItemAt(ordered_item_indices[0]); |
| CreateAndAddButton( |
| CreateVectorIcon(kCloseAllIcon), |
| avatar_menu->GetNumberOfItems() >= 2 |
| ? l10n_util::GetStringFUTF16(IDS_PROFILES_EXIT_PROFILE_BUTTON, |
| active_avatar_item.name) |
| : l10n_util::GetStringUTF16(IDS_PROFILES_CLOSE_ALL_WINDOWS_BUTTON), |
| base::BindRepeating(&ProfileMenuView::OnExitProfileButtonClicked, |
| base::Unretained(this))); |
| } |
| } |
| |
| void ProfileMenuView::AddSupervisedUserDisclaimerView() { |
| AddMenuGroup(); |
| auto* disclaimer = CreateAndAddLabel( |
| avatar_menu_->GetSupervisedUserInformation(), CONTEXT_BODY_TEXT_SMALL); |
| disclaimer->SetAllowCharacterBreak(true); |
| } |
| |
| void ProfileMenuView::AddAutofillHomeView() { |
| if (browser()->profile()->IsGuestSession()) |
| return; |
| |
| AddMenuGroup(); |
| |
| // Passwords. |
| CreateAndAddButton( |
| CreateVectorIcon(kKeyIcon), |
| l10n_util::GetStringUTF16(IDS_PROFILES_PASSWORDS_LINK), |
| base::BindRepeating(&ProfileMenuView::OnPasswordsButtonClicked, |
| base::Unretained(this))); |
| |
| // Credit cards. |
| CreateAndAddButton( |
| CreateVectorIcon(kCreditCardIcon), |
| l10n_util::GetStringUTF16(IDS_PROFILES_CREDIT_CARDS_LINK), |
| base::BindRepeating(&ProfileMenuView::OnCreditCardsButtonClicked, |
| base::Unretained(this))); |
| |
| // Addresses. |
| CreateAndAddButton( |
| CreateVectorIcon(vector_icons::kLocationOnIcon), |
| l10n_util::GetStringUTF16(IDS_PROFILES_ADDRESSES_LINK), |
| base::BindRepeating(&ProfileMenuView::OnAddressesButtonClicked, |
| base::Unretained(this))); |
| } |
| |
| #if defined(GOOGLE_CHROME_BUILD) |
| void ProfileMenuView::AddManageGoogleAccountButton() { |
| AddMenuGroup(false); |
| CreateAndAddButton( |
| GetGoogleIconForUserMenu(GetDefaultIconSize()), |
| l10n_util::GetStringUTF16(IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT), |
| base::BindRepeating(&ProfileMenuView::OnManageGoogleAccountButtonClicked, |
| base::Unretained(this))); |
| } |
| #endif |
| |
| void ProfileMenuView::PostActionPerformed( |
| ProfileMetrics::ProfileDesktopMenu action_performed) { |
| ProfileMetrics::LogProfileDesktopMenu(action_performed); |
| } |
| |
| int ProfileMenuView::GetDiceSigninPromoShowCount() const { |
| return browser()->profile()->GetPrefs()->GetInteger( |
| prefs::kDiceSigninUserMenuPromoCount); |
| } |
| |
| void ProfileMenuView::IncrementDiceSigninPromoShowCount() { |
| browser()->profile()->GetPrefs()->SetInteger( |
| prefs::kDiceSigninUserMenuPromoCount, GetDiceSigninPromoShowCount() + 1); |
| } |