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.
5 #include "chrome/browser/profiles/avatar_menu.h"
8 #include "base/i18n/case_conversion.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/profiler/scoped_tracker.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/browser.h"
22 #include "chrome/browser/ui/browser_dialogs.h"
23 #include "chrome/browser/ui/host_desktop.h"
24 #include "chrome/browser/ui/startup/startup_browser_creator.h"
25 #include "chrome/browser/ui/user_manager.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "components/signin/core/common/profile_management_switches.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/notification_service.h"
31 #include "grit/theme_resources.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/base/resource/resource_bundle.h"
35 #if defined(ENABLE_SUPERVISED_USERS)
36 #include "chrome/browser/supervised_user/supervised_user_service.h"
37 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
40 using content::BrowserThread
;
44 // Constants for the show profile switcher experiment
45 const char kShowProfileSwitcherFieldTrialName
[] = "ShowProfileSwitcher";
46 const char kAlwaysShowSwitcherGroupName
[] = "AlwaysShow";
50 AvatarMenu::AvatarMenu(ProfileInfoInterface
* profile_cache
,
51 AvatarMenuObserver
* observer
,
53 : profile_list_(ProfileList::Create(profile_cache
)),
54 menu_actions_(AvatarMenuActions::Create()),
55 #if defined(ENABLE_SUPERVISED_USERS)
56 supervised_user_observer_(this),
58 profile_info_(profile_cache
),
61 DCHECK(profile_info_
);
62 // Don't DCHECK(browser_) so that unit tests can reuse this ctor.
64 ActiveBrowserChanged(browser_
);
66 // Register this as an observer of the info cache.
67 g_browser_process
->profile_manager()->GetProfileInfoCache().AddObserver(this);
69 #if defined(ENABLE_SUPERVISED_USERS)
70 // Register this as an observer of the SupervisedUserService to be notified
71 // of changes to the custodian info.
73 supervised_user_observer_
.Add(
74 SupervisedUserServiceFactory::GetForProfile(browser_
->profile()));
79 AvatarMenu::~AvatarMenu() {
80 g_browser_process
->profile_manager()->
81 GetProfileInfoCache().RemoveObserver(this);
84 AvatarMenu::Item::Item(size_t menu_index
,
86 const gfx::Image
& icon
)
90 signin_required(false),
91 menu_index(menu_index
),
92 profile_index(profile_index
) {
95 AvatarMenu::Item::~Item() {
99 bool AvatarMenu::ShouldShowAvatarMenu() {
100 if (base::FieldTrialList::FindFullName(kShowProfileSwitcherFieldTrialName
) ==
101 kAlwaysShowSwitcherGroupName
) {
102 // We should only be in this group when multi-profiles is enabled.
103 DCHECK(profiles::IsMultipleProfilesEnabled());
107 // TODO: Eliminate this ifdef. Add a delegate interface for the menu which
108 // would also help remove the Browser dependency in AvatarMenuActions
110 if (profiles::IsMultipleProfilesEnabled()) {
111 #if defined(OS_CHROMEOS)
112 // On ChromeOS the menu will not be shown.
115 return switches::IsNewAvatarMenu() ||
116 (g_browser_process
->profile_manager() &&
117 g_browser_process
->profile_manager()->GetNumberOfProfiles() > 1);
123 bool AvatarMenu::CompareItems(const Item
* item1
, const Item
* item2
) {
124 return base::i18n::ToLower(item1
->name
).compare(
125 base::i18n::ToLower(item2
->name
)) < 0;
128 void AvatarMenu::SwitchToProfile(size_t index
,
130 ProfileMetrics::ProfileOpen metric
) {
131 DCHECK(profiles::IsMultipleProfilesEnabled() ||
132 index
== GetActiveProfileIndex());
133 const Item
& item
= GetItemAt(index
);
135 if (switches::IsNewAvatarMenu()) {
136 // Don't open a browser window for signed-out profiles.
137 if (item
.signin_required
) {
138 UserManager::Show(item
.profile_path
,
139 profiles::USER_MANAGER_NO_TUTORIAL
,
140 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
145 base::FilePath path
=
146 profile_info_
->GetPathOfProfileAtIndex(item
.profile_index
);
148 chrome::HostDesktopType desktop_type
= chrome::GetActiveDesktop();
150 desktop_type
= browser_
->host_desktop_type();
152 profiles::SwitchToProfile(path
, desktop_type
, always_create
,
153 ProfileManager::CreateCallback(),
157 void AvatarMenu::AddNewProfile(ProfileMetrics::ProfileAdd type
) {
158 menu_actions_
->AddNewProfile(type
);
161 void AvatarMenu::EditProfile(size_t index
) {
162 // Get the index in the profile cache from the menu index.
163 size_t profile_index
= profile_list_
->GetItemAt(index
).profile_index
;
165 Profile
* profile
= g_browser_process
->profile_manager()->GetProfileByPath(
166 profile_info_
->GetPathOfProfileAtIndex(profile_index
));
168 menu_actions_
->EditProfile(profile
, profile_index
);
171 void AvatarMenu::RebuildMenu() {
172 profile_list_
->RebuildMenu();
175 size_t AvatarMenu::GetNumberOfItems() const {
176 return profile_list_
->GetNumberOfItems();
179 const AvatarMenu::Item
& AvatarMenu::GetItemAt(size_t index
) const {
180 return profile_list_
->GetItemAt(index
);
182 size_t AvatarMenu::GetActiveProfileIndex() {
184 // During singleton profile deletion, this function can be called with no
185 // profiles in the model - crbug.com/102278 .
186 if (profile_list_
->GetNumberOfItems() == 0)
189 Profile
* active_profile
= NULL
;
191 active_profile
= ProfileManager::GetLastUsedProfile();
193 active_profile
= browser_
->profile();
196 profile_info_
->GetIndexOfProfileWithPath(active_profile
->GetPath());
198 index
= profile_list_
->MenuIndexFromProfileIndex(index
);
199 DCHECK_LT(index
, profile_list_
->GetNumberOfItems());
203 base::string16
AvatarMenu::GetSupervisedUserInformation() const {
204 // |browser_| can be NULL in unit_tests.
205 if (browser_
&& browser_
->profile()->IsSupervised()) {
206 #if defined(ENABLE_SUPERVISED_USERS)
207 SupervisedUserService
* service
=
208 SupervisedUserServiceFactory::GetForProfile(browser_
->profile());
209 base::string16 custodian
=
210 base::UTF8ToUTF16(service
->GetCustodianEmailAddress());
211 if (browser_
->profile()->IsLegacySupervised())
212 return l10n_util::GetStringFUTF16(IDS_SUPERVISED_USER_INFO
, custodian
);
213 base::string16 second_custodian
=
214 base::UTF8ToUTF16(service
->GetSecondCustodianEmailAddress());
215 if (second_custodian
.empty()) {
216 return l10n_util::GetStringFUTF16(IDS_CHILD_INFO_ONE_CUSTODIAN
,
219 return l10n_util::GetStringFUTF16(IDS_CHILD_INFO_TWO_CUSTODIANS
,
220 custodian
, second_custodian
);
224 return base::string16();
227 const gfx::Image
& AvatarMenu::GetSupervisedUserIcon() const {
228 if (browser_
&& browser_
->profile()->IsChild()) {
229 return ResourceBundle::GetSharedInstance().GetNativeImageNamed(
230 IDR_CHILD_USER_ICON
);
232 return ResourceBundle::GetSharedInstance().GetNativeImageNamed(
233 IDR_LEGACY_SUPERVISED_USER_ICON
);
236 void AvatarMenu::ActiveBrowserChanged(Browser
* browser
) {
238 menu_actions_
->ActiveBrowserChanged(browser
);
240 // If browser is not NULL, get the path of its active profile.
243 path
= browser
->profile()->GetPath();
244 profile_list_
->ActiveProfilePathChanged(path
);
247 bool AvatarMenu::ShouldShowAddNewProfileLink() const {
248 return menu_actions_
->ShouldShowAddNewProfileLink();
251 bool AvatarMenu::ShouldShowEditProfileLink() const {
252 return menu_actions_
->ShouldShowEditProfileLink();
255 void AvatarMenu::OnProfileAdded(const base::FilePath
& profile_path
) {
259 void AvatarMenu::OnProfileWasRemoved(const base::FilePath
& profile_path
,
260 const base::string16
& profile_name
) {
264 void AvatarMenu::OnProfileNameChanged(const base::FilePath
& profile_path
,
265 const base::string16
& old_profile_name
) {
269 void AvatarMenu::OnProfileUserNameChanged(const base::FilePath
& profile_path
) {
273 void AvatarMenu::OnProfileAvatarChanged(const base::FilePath
& profile_path
) {
277 void AvatarMenu::OnProfileHighResAvatarLoaded(
278 const base::FilePath
& profile_path
) {
279 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
281 tracked_objects::ScopedTracker
tracking_profile(
282 FROM_HERE_WITH_EXPLICIT_FUNCTION(
283 "461175 AvatarMenu::OnProfileHighResAvatarLoaded"));
287 void AvatarMenu::OnProfileSigninRequiredChanged(
288 const base::FilePath
& profile_path
) {
292 #if defined(ENABLE_SUPERVISED_USERS)
293 void AvatarMenu::OnCustodianInfoChanged() {
296 observer_
->OnAvatarMenuChanged(this);
300 void AvatarMenu::Update() {
303 observer_
->OnAvatarMenuChanged(this);