Home | History | Annotate | Download | only in profiles
      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 
     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 
     81 AvatarMenu::~AvatarMenu() {
     82 }
     83 
     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 
     95 AvatarMenu::Item::~Item() {
     96 }
     97 
     98 // static
     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 
    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 
    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 
    157 void AvatarMenu::AddNewProfile(ProfileMetrics::ProfileAdd type) {
    158   menu_actions_->AddNewProfile(type);
    159 }
    160 
    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 
    171 void AvatarMenu::RebuildMenu() {
    172   profile_list_->RebuildMenu();
    173 }
    174 
    175 size_t AvatarMenu::GetNumberOfItems() const {
    176   return profile_list_->GetNumberOfItems();
    177 }
    178 
    179 const AvatarMenu::Item& AvatarMenu::GetItemAt(size_t index) const {
    180   return profile_list_->GetItemAt(index);
    181 }
    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 
    203 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 
    217 const gfx::Image& AvatarMenu::GetSupervisedUserIcon() const {
    218   return ResourceBundle::GetSharedInstance().GetNativeImageNamed(
    219       IDR_SUPERVISED_USER_ICON);
    220 }
    221 
    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 
    233 bool AvatarMenu::ShouldShowAddNewProfileLink() const {
    234   return menu_actions_->ShouldShowAddNewProfileLink();
    235 }
    236 
    237 bool AvatarMenu::ShouldShowEditProfileLink() const {
    238   return menu_actions_->ShouldShowEditProfileLink();
    239 }
    240 
    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)
    251 void AvatarMenu::OnCustodianInfoChanged() {
    252   RebuildMenu();
    253   if (observer_)
    254     observer_->OnAvatarMenuChanged(this);
    255 }
    256 #endif
    257