• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/browser/ui/user_manager.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "components/signin/core/common/profile_management_switches.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/notification_service.h"
32 #include "grit/theme_resources.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/resource/resource_bundle.h"
35 
36 #if defined(ENABLE_MANAGED_USERS)
37 #include "chrome/browser/supervised_user/supervised_user_service.h"
38 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
39 #endif
40 
41 using content::BrowserThread;
42 
43 namespace {
44 
45 // Constants for the show profile switcher experiment
46 const char kShowProfileSwitcherFieldTrialName[] = "ShowProfileSwitcher";
47 const char kAlwaysShowSwitcherGroupName[] = "AlwaysShow";
48 
49 }  // namespace
50 
AvatarMenu(ProfileInfoInterface * profile_cache,AvatarMenuObserver * observer,Browser * browser)51 AvatarMenu::AvatarMenu(ProfileInfoInterface* profile_cache,
52                        AvatarMenuObserver* observer,
53                        Browser* browser)
54     : profile_list_(ProfileList::Create(profile_cache)),
55       menu_actions_(AvatarMenuActions::Create()),
56 #if defined(ENABLE_MANAGED_USERS)
57       supervised_user_observer_(this),
58 #endif
59       profile_info_(profile_cache),
60       observer_(observer),
61       browser_(browser) {
62   DCHECK(profile_info_);
63   // Don't DCHECK(browser_) so that unit tests can reuse this ctor.
64 
65   ActiveBrowserChanged(browser_);
66 
67   // Register this as an observer of the info cache.
68   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
69       content::NotificationService::AllSources());
70 
71 #if defined(ENABLE_MANAGED_USERS)
72   // Register this as an observer of the SupervisedUserService to be notified
73   // of changes to the custodian info.
74   if (browser_) {
75     supervised_user_observer_.Add(
76         SupervisedUserServiceFactory::GetForProfile(browser_->profile()));
77   }
78 #endif
79 }
80 
~AvatarMenu()81 AvatarMenu::~AvatarMenu() {
82 }
83 
Item(size_t menu_index,size_t profile_index,const gfx::Image & icon)84 AvatarMenu::Item::Item(size_t menu_index,
85                        size_t profile_index,
86                        const gfx::Image& icon)
87     : icon(icon),
88       active(false),
89       signed_in(false),
90       signin_required(false),
91       menu_index(menu_index),
92       profile_index(profile_index) {
93 }
94 
~Item()95 AvatarMenu::Item::~Item() {
96 }
97 
98 // static
ShouldShowAvatarMenu()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());
104     return true;
105   }
106 
107   // TODO: Eliminate this ifdef. Add a delegate interface for the menu which
108   // would also help remove the Browser dependency in AvatarMenuActions
109   // implementations.
110   if (profiles::IsMultipleProfilesEnabled()) {
111 #if defined(OS_CHROMEOS)
112     // On ChromeOS the menu will not be shown.
113     return false;
114 #else
115     return switches::IsNewAvatarMenu() ||
116            (g_browser_process->profile_manager() &&
117             g_browser_process->profile_manager()->GetNumberOfProfiles() > 1);
118 #endif
119   }
120   return false;
121 }
122 
CompareItems(const Item * item1,const Item * item2)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;
126 }
127 
SwitchToProfile(size_t index,bool always_create,ProfileMetrics::ProfileOpen metric)128 void AvatarMenu::SwitchToProfile(size_t index,
129                                  bool always_create,
130                                  ProfileMetrics::ProfileOpen metric) {
131   DCHECK(profiles::IsMultipleProfilesEnabled() ||
132          index == GetActiveProfileIndex());
133   const Item& item = GetItemAt(index);
134 
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);
141       return;
142     }
143   }
144 
145   base::FilePath path =
146       profile_info_->GetPathOfProfileAtIndex(item.profile_index);
147 
148   chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
149   if (browser_)
150     desktop_type = browser_->host_desktop_type();
151 
152   profiles::SwitchToProfile(path, desktop_type, always_create,
153                             ProfileManager::CreateCallback(),
154                             metric);
155 }
156 
AddNewProfile(ProfileMetrics::ProfileAdd type)157 void AvatarMenu::AddNewProfile(ProfileMetrics::ProfileAdd type) {
158   menu_actions_->AddNewProfile(type);
159 }
160 
EditProfile(size_t index)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;
164 
165   Profile* profile = g_browser_process->profile_manager()->GetProfileByPath(
166         profile_info_->GetPathOfProfileAtIndex(profile_index));
167 
168   menu_actions_->EditProfile(profile, profile_index);
169 }
170 
RebuildMenu()171 void AvatarMenu::RebuildMenu() {
172   profile_list_->RebuildMenu();
173 }
174 
GetNumberOfItems() const175 size_t AvatarMenu::GetNumberOfItems() const {
176   return profile_list_->GetNumberOfItems();
177 }
178 
GetItemAt(size_t index) const179 const AvatarMenu::Item& AvatarMenu::GetItemAt(size_t index) const {
180   return profile_list_->GetItemAt(index);
181 }
GetActiveProfileIndex()182 size_t AvatarMenu::GetActiveProfileIndex() {
183 
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)
187     return 0;
188 
189   Profile* active_profile = NULL;
190   if (!browser_)
191     active_profile = ProfileManager::GetLastUsedProfile();
192   else
193     active_profile = browser_->profile();
194 
195   size_t index =
196       profile_info_->GetIndexOfProfileWithPath(active_profile->GetPath());
197 
198   index = profile_list_->MenuIndexFromProfileIndex(index);
199   DCHECK_LT(index, profile_list_->GetNumberOfItems());
200   return index;
201 }
202 
GetSupervisedUserInformation() const203 base::string16 AvatarMenu::GetSupervisedUserInformation() const {
204   // |browser_| can be NULL in unit_tests.
205   if (browser_ && browser_->profile()->IsSupervised()) {
206 #if defined(ENABLE_MANAGED_USERS)
207     SupervisedUserService* service =
208         SupervisedUserServiceFactory::GetForProfile(browser_->profile());
209     base::string16 custodian =
210         base::UTF8ToUTF16(service->GetCustodianEmailAddress());
211     return l10n_util::GetStringFUTF16(IDS_SUPERVISED_USER_INFO, custodian);
212 #endif
213   }
214   return base::string16();
215 }
216 
GetSupervisedUserIcon() const217 const gfx::Image& AvatarMenu::GetSupervisedUserIcon() const {
218   return ResourceBundle::GetSharedInstance().GetNativeImageNamed(
219       IDR_SUPERVISED_USER_ICON);
220 }
221 
ActiveBrowserChanged(Browser * browser)222 void AvatarMenu::ActiveBrowserChanged(Browser* browser) {
223   browser_ = browser;
224   menu_actions_->ActiveBrowserChanged(browser);
225 
226   // If browser is not NULL, get the path of its active profile.
227   base::FilePath path;
228   if (browser)
229     path = browser->profile()->GetPath();
230   profile_list_->ActiveProfilePathChanged(path);
231 }
232 
ShouldShowAddNewProfileLink() const233 bool AvatarMenu::ShouldShowAddNewProfileLink() const {
234   return menu_actions_->ShouldShowAddNewProfileLink();
235 }
236 
ShouldShowEditProfileLink() const237 bool AvatarMenu::ShouldShowEditProfileLink() const {
238   return menu_actions_->ShouldShowEditProfileLink();
239 }
240 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)241 void AvatarMenu::Observe(int type,
242                          const content::NotificationSource& source,
243                          const content::NotificationDetails& details) {
244   DCHECK_EQ(chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, type);
245   RebuildMenu();
246   if (observer_)
247     observer_->OnAvatarMenuChanged(this);
248 }
249 
250 #if defined(ENABLE_MANAGED_USERS)
OnCustodianInfoChanged()251 void AvatarMenu::OnCustodianInfoChanged() {
252   RebuildMenu();
253   if (observer_)
254     observer_->OnAvatarMenuChanged(this);
255 }
256 #endif
257