summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-11 01:25:09 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-11 01:25:09 +0000
commit2f321abba4d5b674558481b308ac58e324e739b3 (patch)
tree667577909f7a24f90bbca2f5fd791ad1f113b6e0
parente9a5fdb1357bd41d05ae406c48040b2155967bfa (diff)
downloadchromium_src-2f321abba4d5b674558481b308ac58e324e739b3.zip
chromium_src-2f321abba4d5b674558481b308ac58e324e739b3.tar.gz
chromium_src-2f321abba4d5b674558481b308ac58e324e739b3.tar.bz2
In the new default multi profile case, all user icons have to be added to the system tray. Made them also clickable to allow to switch to new users.
The final UI might change a bit, but this is basically it. BUG=305064 TEST=ash unit tests, and visual Review URL: https://codereview.chromium.org/26164009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228076 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/system/tray/system_tray.cc6
-rw-r--r--ash/system/tray/system_tray.h3
-rw-r--r--ash/system/tray/system_tray_notifier.cc6
-rw-r--r--ash/system/tray/system_tray_notifier.h1
-rw-r--r--ash/system/user/tray_user.cc232
-rw-r--r--ash/system/user/tray_user.h18
-rw-r--r--ash/system/user/tray_user_unittest.cc57
-rw-r--r--ash/system/user/user_observer.h4
-rw-r--r--chrome/browser/chromeos/system/ash_system_tray_delegate.cc4
9 files changed, 256 insertions, 75 deletions
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 903a4ea0..00fbf74 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -634,6 +634,12 @@ void SystemTray::HideBubble(const TrayBubbleView* bubble_view) {
HideBubbleWithView(bubble_view);
}
+views::View* SystemTray::GetTrayItemViewForTest(SystemTrayItem* item) {
+ std::map<SystemTrayItem*, views::View*>::iterator it =
+ tray_item_map_.find(item);
+ return it == tray_item_map_.end() ? NULL : it->second;
+}
+
bool SystemTray::PerformAction(const ui::Event& event) {
// If we're already showing the default view, hide it; otherwise, show it
// (and hide any popup that's currently shown).
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index 9cd6c25..0860c81 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -139,6 +139,9 @@ class ASH_EXPORT SystemTray : public internal::TrayBackgroundView,
return tray_accessibility_;
}
+ // Get the tray item view (or NULL) for a given |tray_item| in a unit test.
+ views::View* GetTrayItemViewForTest(SystemTrayItem* tray_item);
+
private:
// Creates the default set of items for the sytem tray.
void CreateItems(SystemTrayDelegate* delegate);
diff --git a/ash/system/tray/system_tray_notifier.cc b/ash/system/tray/system_tray_notifier.cc
index f09098d..e2035ad 100644
--- a/ash/system/tray/system_tray_notifier.cc
+++ b/ash/system/tray/system_tray_notifier.cc
@@ -268,6 +268,12 @@ void SystemTrayNotifier::NotifyUserUpdate() {
OnUserUpdate());
}
+void SystemTrayNotifier::NotifyUserAddedToSession() {
+ FOR_EACH_OBSERVER(UserObserver,
+ user_observers_,
+ OnUserAddedToSession());
+}
+
#if defined(OS_CHROMEOS)
void SystemTrayNotifier::NotifyRequestToggleWifi() {
diff --git a/ash/system/tray/system_tray_notifier.h b/ash/system/tray/system_tray_notifier.h
index d92558d..3d7fb0e 100644
--- a/ash/system/tray/system_tray_notifier.h
+++ b/ash/system/tray/system_tray_notifier.h
@@ -111,6 +111,7 @@ public:
void NotifySessionLengthLimitChanged();
void NotifyUpdateRecommended(UpdateObserver::UpdateSeverity severity);
void NotifyUserUpdate();
+ void NotifyUserAddedToSession();
#if defined(OS_CHROMEOS)
void NotifyRequestToggleWifi();
void NotifyEnterpriseDomainChanged();
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
index c11890a..2265319 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/system/user/tray_user.cc
@@ -115,6 +115,16 @@ const int kPublicAccountLogoutButtonBorderImagesHovered[] = {
// Offsetting the popup message relative to the tray menu.
const int kPopupMessageOffset = 25;
+// Switch to a user with the given |user_index|.
+void SwitchUser(ash::MultiProfileIndex user_index) {
+ DCHECK(user_index > 0);
+ ash::SessionStateDelegate* delegate =
+ ash::Shell::GetInstance()->session_state_delegate();
+ ash::MultiProfileUMA::RecordSwitchActiveUser(
+ ash::MultiProfileUMA::SWITCH_ACTIVE_USER_BY_TRAY);
+ delegate->SwitchActiveUser(delegate->GetUserEmail(user_index));
+}
+
} // namespace
namespace ash {
@@ -135,7 +145,7 @@ class RoundedImageView : public views::View {
// receiver's image.
void SetImage(const gfx::ImageSkia& img, const gfx::Size& size);
- // Set the radii of the corners independantly.
+ // Set the radii of the corners independently.
void SetCornerRadii(int top_left,
int top_right,
int bottom_right,
@@ -158,6 +168,24 @@ class RoundedImageView : public views::View {
DISALLOW_COPY_AND_ASSIGN(RoundedImageView);
};
+// An inactive user view which can be clicked to make active. Note that this
+// "button" does not show as a button any click or hover changes.
+class UserSwitcherView : public RoundedImageView {
+ public:
+ UserSwitcherView(int corner_radius, MultiProfileIndex user_index);
+ virtual ~UserSwitcherView() {}
+
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+
+ private:
+ // The user index to activate when the item was clicked. Note that this
+ // index refers to the LRU list of logged in users.
+ MultiProfileIndex user_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserSwitcherView);
+};
+
// The user details shown in public account mode. This is essentially a label
// but with custom painting code as the text is styled with multiple colors and
// contains a link.
@@ -265,11 +293,11 @@ class UserView : public views::View,
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
- void AddLogoutButton(ash::user::LoginStatus login);
- void AddUserCard(SystemTrayItem* owner, ash::user::LoginStatus login);
+ void AddLogoutButton(user::LoginStatus login);
+ void AddUserCard(SystemTrayItem* owner, user::LoginStatus login);
// Create a user icon representation for the user card.
- views::View* CreateIconForUserCard(ash::user::LoginStatus login);
+ views::View* CreateIconForUserCard(user::LoginStatus login);
// Create the additional user card content for the retail logged in mode.
void AddLoggedInRetailModeUserCardContent();
@@ -295,7 +323,7 @@ class UserView : public views::View,
// |views::View|.
bool is_user_card_;
views::View* logout_button_;
- scoped_ptr<ash::PopupMessage> popup_message_;
+ scoped_ptr<PopupMessage> popup_message_;
scoped_ptr<views::Widget> add_menu_option_;
// True when the add user panel is visible but not activatable.
@@ -410,6 +438,27 @@ void RoundedImageView::OnPaint(gfx::Canvas* canvas) {
path, paint);
}
+UserSwitcherView::UserSwitcherView(int corner_radius,
+ MultiProfileIndex user_index)
+ : RoundedImageView(corner_radius, false),
+ user_index_(user_index) {
+ SetEnabled(true);
+}
+
+void UserSwitcherView::OnMouseEvent(ui::MouseEvent* event) {
+ if (event->type() == ui::ET_MOUSE_PRESSED) {
+ SwitchUser(user_index_);
+ event->SetHandled();
+ }
+}
+
+void UserSwitcherView::OnTouchEvent(ui::TouchEvent* event) {
+ if (event->type() == ui::ET_TOUCH_PRESSED) {
+ SwitchUser(user_index_);
+ event->SetHandled();
+ }
+}
+
PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner,
int used_width)
: learn_more_(NULL) {
@@ -424,13 +473,12 @@ PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner,
// Note that since this is a public account it always has to be the primary
// user.
base::string16 display_name =
- ash::Shell::GetInstance()->session_state_delegate()->
- GetUserDisplayName(0);
+ Shell::GetInstance()->session_state_delegate()->GetUserDisplayName(0);
RemoveChars(display_name, kDisplayNameMark, &display_name);
display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0];
// Retrieve the domain managing the device and wrap it with markers.
base::string16 domain = UTF8ToUTF16(
- ash::Shell::GetInstance()->system_tray_delegate()->GetEnterpriseDomain());
+ Shell::GetInstance()->system_tray_delegate()->GetEnterpriseDomain());
RemoveChars(domain, kDisplayNameMark, &domain);
base::i18n::WrapStringWithLTRFormatting(&domain);
// Retrieve the label text, inserting the display name and domain.
@@ -529,7 +577,7 @@ void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) {
void PublicAccountUserDetails::LinkClicked(views::Link* source,
int event_flags) {
DCHECK_EQ(source, learn_more_);
- ash::Shell::GetInstance()->system_tray_delegate()->ShowPublicAccountInfo();
+ Shell::GetInstance()->system_tray_delegate()->ShowPublicAccountInfo();
}
void PublicAccountUserDetails::CalculatePreferredSize(SystemTrayItem* owner,
@@ -631,7 +679,7 @@ void UserCard::ShowActive() {
}
UserView::UserView(SystemTrayItem* owner,
- ash::user::LoginStatus login,
+ user::LoginStatus login,
MultiProfileIndex index)
: multiprofile_index_(index),
user_card_view_(NULL),
@@ -639,13 +687,13 @@ UserView::UserView(SystemTrayItem* owner,
is_user_card_(false),
logout_button_(NULL),
add_user_visible_but_disabled_(false) {
- CHECK_NE(ash::user::LOGGED_IN_NONE, login);
+ CHECK_NE(user::LOGGED_IN_NONE, login);
if (!index) {
// Only the logged in user will have a background. All other users will have
// to allow the TrayPopupContainer highlighting the menu line.
set_background(views::Background::CreateSolidBackground(
- login == ash::user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
- kBackgroundColor));
+ login == user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
+ kBackgroundColor));
}
SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
kTrayPopupPaddingBetweenItems));
@@ -744,16 +792,12 @@ void UserView::Layout() {
void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
if (sender == logout_button_) {
- ash::Shell::GetInstance()->system_tray_delegate()->SignOut();
+ Shell::GetInstance()->system_tray_delegate()->SignOut();
} else if (sender == user_card_view_ && SupportsMultiProfile()) {
if (!multiprofile_index_) {
ToggleAddUserMenuOption();
} else {
- ash::SessionStateDelegate* delegate =
- ash::Shell::GetInstance()->session_state_delegate();
- MultiProfileUMA::RecordSwitchActiveUser(
- MultiProfileUMA::SWITCH_ACTIVE_USER_BY_TRAY);
- delegate->SwitchActiveUser(delegate->GetUserEmail(multiprofile_index_));
+ SwitchUser(multiprofile_index_);
// Since the user list is about to change the system menu should get
// closed.
owner_->system_tray()->CloseSystemBubble();
@@ -762,20 +806,20 @@ void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
sender == add_menu_option_->GetContentsView()) {
// Let the user add another account to the session.
MultiProfileUMA::RecordSigninUser(MultiProfileUMA::SIGNIN_USER_BY_TRAY);
- ash::Shell::GetInstance()->system_tray_delegate()->ShowUserLogin();
+ Shell::GetInstance()->system_tray_delegate()->ShowUserLogin();
} else {
NOTREACHED();
}
}
-void UserView::AddLogoutButton(ash::user::LoginStatus login) {
- const base::string16 title = ash::user::GetLocalizedSignOutStringForStatus(
- login, true);
+void UserView::AddLogoutButton(user::LoginStatus login) {
+ const base::string16 title = user::GetLocalizedSignOutStringForStatus(login,
+ true);
TrayPopupLabelButton* logout_button = new TrayPopupLabelButton(this, title);
logout_button->SetAccessibleName(title);
logout_button_ = logout_button;
// In public account mode, the logout button border has a custom color.
- if (login == ash::user::LOGGED_IN_PUBLIC) {
+ if (login == user::LOGGED_IN_PUBLIC) {
TrayPopupLabelButtonBorder* border =
static_cast<TrayPopupLabelButtonBorder*>(logout_button_->border());
border->SetPainter(false, views::Button::STATE_NORMAL,
@@ -791,14 +835,13 @@ void UserView::AddLogoutButton(ash::user::LoginStatus login) {
AddChildView(logout_button_);
}
-void UserView::AddUserCard(SystemTrayItem* owner,
- ash::user::LoginStatus login) {
+void UserView::AddUserCard(SystemTrayItem* owner, user::LoginStatus login) {
// Add padding around the panel.
set_border(views::Border::CreateEmptyBorder(
kUserCardVerticalPadding, kTrayPopupPaddingHorizontal,
kUserCardVerticalPadding, kTrayPopupPaddingHorizontal));
- if (SupportsMultiProfile() && login != ash::user::LOGGED_IN_RETAIL_MODE) {
+ if (SupportsMultiProfile() && login != user::LOGGED_IN_RETAIL_MODE) {
user_card_view_ = new UserCard(this, multiprofile_index_ == 0);
is_user_card_ = true;
} else {
@@ -810,7 +853,7 @@ void UserView::AddUserCard(SystemTrayItem* owner,
views::BoxLayout::kHorizontal, 0, 0 , kTrayPopupPaddingBetweenItems));
AddChildViewAt(user_card_view_, 0);
- if (login == ash::user::LOGGED_IN_RETAIL_MODE) {
+ if (login == user::LOGGED_IN_RETAIL_MODE) {
AddLoggedInRetailModeUserCardContent();
return;
}
@@ -819,7 +862,7 @@ void UserView::AddUserCard(SystemTrayItem* owner,
user_card_view_->SetEnabled(true);
user_card_view_->set_notify_enter_exit_on_child(true);
- if (login == ash::user::LOGGED_IN_PUBLIC) {
+ if (login == user::LOGGED_IN_PUBLIC) {
AddLoggedInPublicModeUserCardContent(owner);
return;
}
@@ -838,13 +881,13 @@ void UserView::AddUserCard(SystemTrayItem* owner,
kUserCardVerticalPadding,
kTrayPopupPaddingHorizontal));
}
- ash::SessionStateDelegate* delegate =
- ash::Shell::GetInstance()->session_state_delegate();
+ SessionStateDelegate* delegate =
+ Shell::GetInstance()->session_state_delegate();
views::Label* username = NULL;
ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
if (!multiprofile_index_) {
base::string16 user_name_string =
- login == ash::user::LOGGED_IN_GUEST ?
+ login == user::LOGGED_IN_GUEST ?
bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL) :
delegate->GetUserDisplayName(multiprofile_index_);
if (!user_name_string.empty()) {
@@ -854,9 +897,9 @@ void UserView::AddUserCard(SystemTrayItem* owner,
}
views::Label* additional = NULL;
- if (login != ash::user::LOGGED_IN_GUEST) {
+ if (login != user::LOGGED_IN_GUEST) {
base::string16 user_email_string =
- login == ash::user::LOGGED_IN_LOCALLY_MANAGED ?
+ login == user::LOGGED_IN_LOCALLY_MANAGED ?
bundle.GetLocalizedString(
IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL) :
UTF8ToUTF16(delegate->GetUserEmail(multiprofile_index_));
@@ -893,17 +936,17 @@ void UserView::AddUserCard(SystemTrayItem* owner,
}
}
-views::View* UserView::CreateIconForUserCard(ash::user::LoginStatus login) {
+views::View* UserView::CreateIconForUserCard(user::LoginStatus login) {
RoundedImageView* icon = new RoundedImageView(kProfileRoundedCornerRadius,
multiprofile_index_ == 0);
icon->SetEnabled(false);
- if (login == ash::user::LOGGED_IN_GUEST) {
+ if (login == user::LOGGED_IN_GUEST) {
icon->SetImage(*ui::ResourceBundle::GetSharedInstance().
GetImageNamed(IDR_AURA_UBER_TRAY_GUEST_ICON).ToImageSkia(),
gfx::Size(kUserIconSize, kUserIconSize));
} else {
icon->SetImage(
- ash::Shell::GetInstance()->session_state_delegate()->
+ Shell::GetInstance()->session_state_delegate()->
GetUserImage(multiprofile_index_),
gfx::Size(kUserIconSize, kUserIconSize));
}
@@ -921,8 +964,7 @@ void UserView::AddLoggedInRetailModeUserCardContent() {
}
void UserView::AddLoggedInPublicModeUserCardContent(SystemTrayItem* owner) {
- user_card_view_->AddChildView(
- CreateIconForUserCard(ash::user::LOGGED_IN_PUBLIC));
+ user_card_view_->AddChildView(CreateIconForUserCard(user::LOGGED_IN_PUBLIC));
user_card_view_->AddChildView(new PublicAccountUserDetails(
owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems));
}
@@ -939,7 +981,7 @@ void UserView::ToggleAddUserMenuOption() {
// item since it will destroyed automatically before the menu / user menu item
// gets destroyed..
const SessionStateDelegate* session_state_delegate =
- ash::Shell::GetInstance()->session_state_delegate();
+ Shell::GetInstance()->session_state_delegate();
add_user_visible_but_disabled_ =
session_state_delegate->NumberOfLoggedInUsers() >=
session_state_delegate->GetMaximumNumberOfLoggedInUsers();
@@ -992,8 +1034,8 @@ void UserView::ToggleAddUserMenuOption() {
bool UserView::SupportsMultiProfile() {
// Until the final UX team verdict has been given we disable this
// functionality.
- return ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
- ash::switches::ShowMultiProfileShelfMenu();
+ return Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
+ switches::ShowMultiProfileShelfMenu();
}
AddUserView::AddUserView(UserCard* owner, views::ButtonListener* listener)
@@ -1034,7 +1076,7 @@ void AddUserView::AddContent() {
set_notify_enter_exit_on_child(true);
const SessionStateDelegate* delegate =
- ash::Shell::GetInstance()->session_state_delegate();
+ Shell::GetInstance()->session_state_delegate();
bool enable = delegate->NumberOfLoggedInUsers() <
delegate->GetMaximumNumberOfLoggedInUsers();
@@ -1104,9 +1146,9 @@ gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const {
views::View* TrayUser::CreateTrayView(user::LoginStatus status) {
CHECK(layout_view_ == NULL);
- // Only the current user gets an icon. All other users will only be
- // represented in the tray menu.
- if (multiprofile_index_)
+ // When the full multi profile mode is used, only the active user will be
+ // shown in the system tray, otherwise all users which are logged in.
+ if (GetTrayIndex() && switches::UseFullMultiProfileMode())
return NULL;
layout_view_ = new views::View();
@@ -1124,7 +1166,7 @@ views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
CHECK(user_ == NULL);
const SessionStateDelegate* session_state_delegate =
- ash::Shell::GetInstance()->session_state_delegate();
+ Shell::GetInstance()->session_state_delegate();
int logged_in_users = session_state_delegate->NumberOfLoggedInUsers();
// If there are multiple users logged in, the users will be separated from the
@@ -1199,7 +1241,15 @@ void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) {
label_ = NULL;
}
if (need_avatar) {
- avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius, true);
+ MultiProfileIndex tray_index = GetTrayIndex();
+ if (!tray_index) {
+ // The active user (index #0) will always be the first.
+ avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius, true);
+ } else {
+ // All other users will be inactive users.
+ avatar_ = new tray::UserSwitcherView(kProfileRoundedCornerRadius,
+ tray_index);
+ }
layout_view_->AddChildView(avatar_);
} else {
avatar_ = NULL;
@@ -1214,35 +1264,28 @@ void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) {
label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL));
}
- if (avatar_ && ash::switches::UseAlternateShelfLayout()) {
- avatar_->SetCornerRadii(0,
- kUserIconLargeCornerRadius,
- kUserIconLargeCornerRadius,
- 0);
+ if (avatar_ && switches::UseAlternateShelfLayout()) {
+ int corner_radius = GetTrayItemRadius();
+ avatar_->SetCornerRadii(0, corner_radius, corner_radius, 0);
avatar_->set_border(NULL);
}
UpdateAvatarImage(status);
// Update layout after setting label_ and avatar_ with new login status.
- if (Shell::GetPrimaryRootWindowController()->shelf())
- UpdateAfterShelfAlignmentChange(
- Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
- GetAlignment());
+ UpdateLayoutOfItem();
}
void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
// Inactive users won't have a layout.
if (!layout_view_)
return;
+ int corner_radius = GetTrayItemRadius();
if (alignment == SHELF_ALIGNMENT_BOTTOM ||
alignment == SHELF_ALIGNMENT_TOP) {
if (avatar_) {
- if (ash::switches::UseAlternateShelfLayout()) {
+ if (switches::UseAlternateShelfLayout()) {
avatar_->set_border(NULL);
- avatar_->SetCornerRadii(0,
- kUserIconLargeCornerRadius,
- kUserIconLargeCornerRadius,
- 0);
+ avatar_->SetCornerRadii(0, corner_radius, corner_radius, 0);
} else {
avatar_->set_border(views::Border::CreateEmptyBorder(
0, kTrayImageItemHorizontalPaddingBottomAlignment + 2,
@@ -1259,12 +1302,9 @@ void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
0, 0, kUserLabelToIconPadding));
} else {
if (avatar_) {
- if (ash::switches::UseAlternateShelfLayout()) {
+ if (switches::UseAlternateShelfLayout()) {
avatar_->set_border(NULL);
- avatar_->SetCornerRadii(0,
- 0,
- kUserIconLargeCornerRadius,
- kUserIconLargeCornerRadius);
+ avatar_->SetCornerRadii(0, 0, corner_radius, corner_radius);
} else {
SetTrayImageItemBorder(avatar_, alignment);
}
@@ -1287,17 +1327,67 @@ void TrayUser::OnUserUpdate() {
GetUserLoginStatus());
}
+void TrayUser::OnUserAddedToSession() {
+ SessionStateDelegate* session_state_delegate =
+ Shell::GetInstance()->session_state_delegate();
+ // Only create views for user items which are logged in.
+ if (GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers())
+ return;
+
+ // Enforce a layout change that newly added items become visible.
+ UpdateLayoutOfItem();
+
+ // Update the user item.
+ UpdateAvatarImage(
+ Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
+}
+
void TrayUser::UpdateAvatarImage(user::LoginStatus status) {
- if (!avatar_)
+ SessionStateDelegate* session_state_delegate =
+ Shell::GetInstance()->session_state_delegate();
+ if (!avatar_ ||
+ GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers())
return;
- int icon_size = ash::switches::UseAlternateShelfLayout() ?
+ int icon_size = switches::UseAlternateShelfLayout() ?
kUserIconLargeSize : kUserIconSize;
avatar_->SetImage(
- ash::Shell::GetInstance()->session_state_delegate()->GetUserImage(
- multiprofile_index_),
+ Shell::GetInstance()->session_state_delegate()->GetUserImage(
+ GetTrayIndex()),
gfx::Size(icon_size, icon_size));
+
+ // Unit tests might come here with no images for some users.
+ if (avatar_->size().IsEmpty())
+ avatar_->SetSize(gfx::Size(icon_size, icon_size));
+}
+
+MultiProfileIndex TrayUser::GetTrayIndex() {
+ Shell* shell = Shell::GetInstance();
+ // If multi profile is not enabled we can use the normal index.
+ if (!shell->delegate()->IsMultiProfilesEnabled())
+ return multiprofile_index_;
+ // In case of multi profile we need to mirror the indices since the system
+ // tray items are in the reverse order then the menu items.
+ return shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers() -
+ multiprofile_index_;
+}
+
+int TrayUser::GetTrayItemRadius() {
+ SessionStateDelegate* delegate =
+ Shell::GetInstance()->session_state_delegate();
+ bool is_last_item = GetTrayIndex() == (delegate->NumberOfLoggedInUsers() - 1);
+ return is_last_item ? kUserIconLargeCornerRadius : 0;
+}
+
+void TrayUser::UpdateLayoutOfItem() {
+ internal::RootWindowController* controller =
+ internal::GetRootWindowController(
+ system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow());
+ if (controller && controller->shelf()) {
+ UpdateAfterShelfAlignmentChange(
+ controller->GetShelfLayoutManager()->GetAlignment());
+ }
}
} // namespace internal
diff --git a/ash/system/user/tray_user.h b/ash/system/user/tray_user.h
index 70b54bb..9de7e4b 100644
--- a/ash/system/user/tray_user.h
+++ b/ash/system/user/tray_user.h
@@ -31,10 +31,10 @@ class RoundedImageView;
class ASH_EXPORT TrayUser : public SystemTrayItem,
public UserObserver {
public:
- // The given |multiprofile_index| is the number of the user in a multi profile
- // scenario. Index #0 is the running user, the other indices are other
- // logged in users (if there are any). Only index #0 will add an icon to
- // the system tray.
+ // The given |multiprofile_index| is the user number in a multi profile
+ // scenario. Index #0 is the running user, the other indices are other logged
+ // in users (if there are any). Depending on the multi user mode, there will
+ // be either one (index #0) or all users be visible in the system tray.
TrayUser(SystemTray* system_tray, MultiProfileIndex index);
virtual ~TrayUser();
@@ -67,9 +67,19 @@ class ASH_EXPORT TrayUser : public SystemTrayItem,
// Overridden from UserObserver.
virtual void OnUserUpdate() OVERRIDE;
+ virtual void OnUserAddedToSession() OVERRIDE;
void UpdateAvatarImage(user::LoginStatus status);
+ // Get the user index which should be used for the tray icon of this item.
+ MultiProfileIndex GetTrayIndex();
+
+ // Return the radius for the tray item to use.
+ int GetTrayItemRadius();
+
+ // Updates the layout of this item.
+ void UpdateLayoutOfItem();
+
// The user index to use.
MultiProfileIndex multiprofile_index_;
diff --git a/ash/system/user/tray_user_unittest.cc b/ash/system/user/tray_user_unittest.cc
index d8115dc..bafe772 100644
--- a/ash/system/user/tray_user_unittest.cc
+++ b/ash/system/user/tray_user_unittest.cc
@@ -20,6 +20,10 @@
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
+#if defined(OS_CHROMEOS)
+#include "ash/system/tray/system_tray_notifier.h"
+#endif
+
namespace ash {
namespace internal {
@@ -235,6 +239,59 @@ TEST_F(TrayUserTest, MutiUserModeButtonClicks) {
EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserEmail(1));
tray()->CloseSystemBubble();
}
+
+// Make sure that we show items for all users in the tray accordingly.
+TEST_F(TrayUserTest, CheckTrayUserItems) {
+ InitializeParameters(1, true);
+
+ int max_users = delegate()->GetMaximumNumberOfLoggedInUsers();
+ // Checking now for each amount of users that the proper items are visible in
+ // the tray. The proper item is hereby:
+ // 3 -> User #1
+ // 2 -> User #2
+ // 1 -> User #3
+ // 0 -> Separator (never shown)
+ // Note: Tray items are required to populate system tray items as well as the
+ // system tray menu. The system tray menu changes it's appearance with the
+ // addition of more users, but the system tray does not create new items after
+ // it got created. The logic to know if an item is present, not present or
+ // even "only" a "separator" is inside the tray user items. This test tries
+ // to test as close as possible the "real thing" and as such the break is
+ // included.
+ for (int j = 1; j <= max_users; j++) {
+ // We simulate the user addition by telling the delegate the new number of
+ // users, then change all user tray items and finally tell the tray to
+ // re-layout itself.
+ delegate()->set_logged_in_users(j);
+ Shell::GetInstance()->system_tray_notifier()->NotifyUserAddedToSession();
+ tray()->Layout();
+
+ // Check that the tray items are being shown in the reverse order.
+ for (int i = 0; i <= max_users; i++) {
+ gfx::Rect rect = tray()->
+ GetTrayItemViewForTest(tray_user(i))->GetBoundsInScreen();
+ if (max_users - i < j)
+ EXPECT_FALSE(rect.IsEmpty());
+ else
+ EXPECT_TRUE(rect.IsEmpty());
+ }
+ }
+
+ // Click on the last item to see that the user changes.
+ aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+ generator.set_async(false);
+
+ // Switch to a new user - again, note that we have to click on the reverse
+ // item in the list (1 -> user 3).
+ gfx::Point point =
+ tray()->GetTrayItemViewForTest(tray_user(1))->
+ GetBoundsInScreen().CenterPoint();
+
+ generator.MoveMouseTo(point.x(), point.y());
+ generator.ClickLeftButton();
+ EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserEmail(2));
+}
+
#endif
} // namespace internal
diff --git a/ash/system/user/user_observer.h b/ash/system/user/user_observer.h
index 2968d95..64c2b9d 100644
--- a/ash/system/user/user_observer.h
+++ b/ash/system/user/user_observer.h
@@ -13,7 +13,11 @@ class ASH_EXPORT UserObserver {
public:
virtual ~UserObserver() {}
+ // A user got updated / changed.
virtual void OnUserUpdate() = 0;
+
+ // A user was added to the existing session.
+ virtual void OnUserAddedToSession() = 0;
};
} // namespace ash
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index 2d854ec..917d8a3 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -1197,6 +1197,10 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
GetSystemTrayNotifier()->NotifyUserUpdate();
}
+ virtual void UserAddedToSession(const std::string& user_id) OVERRIDE {
+ GetSystemTrayNotifier()->NotifyUserAddedToSession();
+ }
+
scoped_ptr<base::WeakPtrFactory<SystemTrayDelegate> > ui_weak_ptr_factory_;
scoped_ptr<content::NotificationRegistrar> registrar_;
scoped_ptr<PrefChangeRegistrar> local_state_registrar_;