1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/profiles/avatar_menu.h" 6 7 #include "ash/ash_switches.h" 8 #include "base/bind.h" 9 #include "base/i18n/case_conversion.h" 10 #include "base/metrics/field_trial.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/chrome_notification_types.h" 14 #include "chrome/browser/profiles/avatar_menu_actions.h" 15 #include "chrome/browser/profiles/avatar_menu_observer.h" 16 #include "chrome/browser/profiles/profile_list.h" 17 #include "chrome/browser/profiles/profile_manager.h" 18 #include "chrome/browser/profiles/profile_metrics.h" 19 #include "chrome/browser/profiles/profile_window.h" 20 #include "chrome/browser/profiles/profiles_state.h" 21 #include "chrome/browser/ui/ash/chrome_shell_delegate.h" 22 #include "chrome/browser/ui/browser.h" 23 #include "chrome/browser/ui/browser_dialogs.h" 24 #include "chrome/browser/ui/host_desktop.h" 25 #include "chrome/browser/ui/startup/startup_browser_creator.h" 26 #include "chrome/common/chrome_switches.h" 27 #include "content/public/browser/browser_thread.h" 28 #include "content/public/browser/notification_service.h" 29 #include "grit/generated_resources.h" 30 #include "grit/theme_resources.h" 31 #include "ui/base/l10n/l10n_util.h" 32 #include "ui/base/resource/resource_bundle.h" 33 34 #if defined(ENABLE_MANAGED_USERS) 35 #include "chrome/browser/managed_mode/managed_user_service.h" 36 #include "chrome/browser/managed_mode/managed_user_service_factory.h" 37 #endif 38 39 using content::BrowserThread; 40 41 namespace { 42 43 // Constants for the show profile switcher experiment 44 const char kShowProfileSwitcherFieldTrialName[] = "ShowProfileSwitcher"; 45 const char kAlwaysShowSwitcherGroupName[] = "AlwaysShow"; 46 47 } // namespace 48 49 AvatarMenu::AvatarMenu(ProfileInfoInterface* profile_cache, 50 AvatarMenuObserver* observer, 51 Browser* browser) 52 : profile_list_(ProfileList::Create(profile_cache)), 53 menu_actions_(AvatarMenuActions::Create()), 54 profile_info_(profile_cache), 55 observer_(observer), 56 browser_(browser) { 57 DCHECK(profile_info_); 58 // Don't DCHECK(browser_) so that unit tests can reuse this ctor. 59 60 ActiveBrowserChanged(browser_); 61 62 // Register this as an observer of the info cache. 63 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, 64 content::NotificationService::AllSources()); 65 } 66 67 AvatarMenu::~AvatarMenu() { 68 } 69 70 AvatarMenu::Item::Item(size_t menu_index, 71 size_t profile_index, 72 const gfx::Image& icon) 73 : icon(icon), 74 active(false), 75 signed_in(false), 76 signin_required(false), 77 menu_index(menu_index), 78 profile_index(profile_index) { 79 } 80 81 AvatarMenu::Item::~Item() { 82 } 83 84 // static 85 bool AvatarMenu::ShouldShowAvatarMenu() { 86 if (base::FieldTrialList::FindFullName(kShowProfileSwitcherFieldTrialName) == 87 kAlwaysShowSwitcherGroupName) { 88 // We should only be in this group when multi-profiles is enabled. 89 DCHECK(profiles::IsMultipleProfilesEnabled()); 90 return true; 91 } 92 93 // TODO: Eliminate this ifdef. Add a delegate interface for the menu which 94 // would also help remove the Browser dependency in AvatarMenuActions 95 // implementations. 96 if (profiles::IsMultipleProfilesEnabled()) { 97 #if defined(OS_CHROMEOS) 98 // On ChromeOS the menu will be shown in M-31 mode when it is possible to 99 // have two users logged in at the same time. 100 return ash::switches::UseFullMultiProfileMode() && 101 ChromeShellDelegate::instance() && 102 ChromeShellDelegate::instance()->IsMultiProfilesEnabled(); 103 #else 104 return profiles::IsNewProfileManagementEnabled() || 105 (g_browser_process->profile_manager() && 106 g_browser_process->profile_manager()->GetNumberOfProfiles() > 1); 107 #endif 108 } 109 return false; 110 } 111 112 bool AvatarMenu::CompareItems(const Item* item1, const Item* item2) { 113 return base::i18n::ToLower(item1->name).compare( 114 base::i18n::ToLower(item2->name)) < 0; 115 } 116 117 void AvatarMenu::SwitchToProfile(size_t index, bool always_create) { 118 DCHECK(profiles::IsMultipleProfilesEnabled() || 119 index == GetActiveProfileIndex()); 120 const Item& item = GetItemAt(index); 121 122 if (profiles::IsNewProfileManagementEnabled()) { 123 // Don't open a browser window for signed-out profiles. 124 if (item.signin_required) { 125 chrome::ShowUserManager(item.profile_path); 126 return; 127 } 128 } 129 130 base::FilePath path = 131 profile_info_->GetPathOfProfileAtIndex(item.profile_index); 132 133 chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); 134 if (browser_) 135 desktop_type = browser_->host_desktop_type(); 136 137 profiles::SwitchToProfile(path, desktop_type, always_create, 138 profiles::ProfileSwitchingDoneCallback()); 139 ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_ICON); 140 } 141 142 void AvatarMenu::AddNewProfile(ProfileMetrics::ProfileAdd type) { 143 menu_actions_->AddNewProfile(type); 144 } 145 146 void AvatarMenu::EditProfile(size_t index) { 147 // Get the index in the profile cache from the menu index. 148 size_t profile_index = profile_list_->GetItemAt(index).profile_index; 149 150 Profile* profile = g_browser_process->profile_manager()->GetProfileByPath( 151 profile_info_->GetPathOfProfileAtIndex(profile_index)); 152 153 menu_actions_->EditProfile(profile, profile_index); 154 } 155 156 void AvatarMenu::RebuildMenu() { 157 profile_list_->RebuildMenu(); 158 } 159 160 size_t AvatarMenu::GetNumberOfItems() const { 161 return profile_list_->GetNumberOfItems(); 162 } 163 164 const AvatarMenu::Item& AvatarMenu::GetItemAt(size_t index) const { 165 return profile_list_->GetItemAt(index); 166 } 167 size_t AvatarMenu::GetActiveProfileIndex() { 168 169 // During singleton profile deletion, this function can be called with no 170 // profiles in the model - crbug.com/102278 . 171 if (profile_list_->GetNumberOfItems() == 0) 172 return 0; 173 174 Profile* active_profile = NULL; 175 if (!browser_) 176 active_profile = ProfileManager::GetLastUsedProfile(); 177 else 178 active_profile = browser_->profile(); 179 180 size_t index = 181 profile_info_->GetIndexOfProfileWithPath(active_profile->GetPath()); 182 183 index = profile_list_->MenuIndexFromProfileIndex(index); 184 DCHECK_LT(index, profile_list_->GetNumberOfItems()); 185 return index; 186 } 187 188 base::string16 AvatarMenu::GetManagedUserInformation() const { 189 // |browser_| can be NULL in unit_tests. 190 if (browser_ && browser_->profile()->IsManaged()) { 191 #if defined(ENABLE_MANAGED_USERS) 192 ManagedUserService* service = ManagedUserServiceFactory::GetForProfile( 193 browser_->profile()); 194 base::string16 custodian = UTF8ToUTF16(service->GetCustodianEmailAddress()); 195 return l10n_util::GetStringFUTF16(IDS_MANAGED_USER_INFO, custodian); 196 #endif 197 } 198 return base::string16(); 199 } 200 201 const gfx::Image& AvatarMenu::GetManagedUserIcon() const { 202 return ResourceBundle::GetSharedInstance().GetNativeImageNamed( 203 IDR_MANAGED_USER_ICON); 204 } 205 206 void AvatarMenu::ActiveBrowserChanged(Browser* browser) { 207 browser_ = browser; 208 menu_actions_->ActiveBrowserChanged(browser); 209 210 // If browser is not NULL, get the path of its active profile. 211 base::FilePath path; 212 if (browser) 213 path = browser->profile()->GetPath(); 214 profile_list_->ActiveProfilePathChanged(path); 215 } 216 217 bool AvatarMenu::ShouldShowAddNewProfileLink() const { 218 return menu_actions_->ShouldShowAddNewProfileLink(); 219 } 220 221 bool AvatarMenu::ShouldShowEditProfileLink() const { 222 return menu_actions_->ShouldShowEditProfileLink(); 223 } 224 225 void AvatarMenu::Observe(int type, 226 const content::NotificationSource& source, 227 const content::NotificationDetails& details) { 228 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, type); 229 RebuildMenu(); 230 if (observer_) 231 observer_->OnAvatarMenuChanged(this); 232 } 233