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 "ash/system/user/tray_user.h"
7 #include "ash/ash_switches.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/session/session_state_delegate.h"
10 #include "ash/shelf/shelf_layout_manager.h"
11 #include "ash/shell_delegate.h"
12 #include "ash/system/tray/system_tray.h"
13 #include "ash/system/tray/system_tray_delegate.h"
14 #include "ash/system/tray/system_tray_notifier.h"
15 #include "ash/system/tray/tray_constants.h"
16 #include "ash/system/tray/tray_item_view.h"
17 #include "ash/system/tray/tray_utils.h"
18 #include "ash/system/user/accounts_detailed_view.h"
19 #include "ash/system/user/rounded_image_view.h"
20 #include "ash/system/user/user_view.h"
21 #include "base/logging.h"
22 #include "base/strings/string16.h"
23 #include "components/user_manager/user_info.h"
24 #include "grit/ash_strings.h"
25 #include "ui/aura/window.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/gfx/image/image.h"
28 #include "ui/views/border.h"
29 #include "ui/views/controls/label.h"
30 #include "ui/views/layout/box_layout.h"
31 #include "ui/views/view.h"
32 #include "ui/views/widget/widget.h"
36 const int kUserLabelToIconPadding
= 5;
42 TrayUser::TrayUser(SystemTray
* system_tray
, MultiProfileIndex index
)
43 : SystemTrayItem(system_tray
),
44 multiprofile_index_(index
),
49 Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this);
52 TrayUser::~TrayUser() {
53 Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this);
56 TrayUser::TestState
TrayUser::GetStateForTest() const {
59 return user_
->GetStateForTest();
62 gfx::Size
TrayUser::GetLayoutSizeForTest() const {
64 return gfx::Size(0, 0);
66 return layout_view_
->size();
70 gfx::Rect
TrayUser::GetUserPanelBoundsInScreenForTest() const {
72 return user_
->GetBoundsInScreenOfUserButtonForTest();
75 void TrayUser::UpdateAfterLoginStatusChangeForTest(user::LoginStatus status
) {
76 UpdateAfterLoginStatusChange(status
);
79 views::View
* TrayUser::CreateTrayView(user::LoginStatus status
) {
80 CHECK(layout_view_
== NULL
);
82 layout_view_
= new views::View
;
83 layout_view_
->SetLayoutManager(
84 new views::BoxLayout(views::BoxLayout::kHorizontal
,
85 0, 0, kUserLabelToIconPadding
));
86 UpdateAfterLoginStatusChange(status
);
90 views::View
* TrayUser::CreateDefaultView(user::LoginStatus status
) {
91 if (status
== user::LOGGED_IN_NONE
)
93 const SessionStateDelegate
* session_state_delegate
=
94 Shell::GetInstance()->session_state_delegate();
96 // If the screen is locked or a system modal dialog box is shown, show only
97 // the currently active user.
98 if (multiprofile_index_
&&
99 (session_state_delegate
->IsUserSessionBlocked() ||
100 Shell::GetInstance()->IsSystemModalWindowOpen()))
103 CHECK(user_
== NULL
);
105 int logged_in_users
= session_state_delegate
->NumberOfLoggedInUsers();
107 // Do not show more UserView's then there are logged in users.
108 if (multiprofile_index_
>= logged_in_users
)
111 user_
= new tray::UserView(this, status
, multiprofile_index_
, false);
115 views::View
* TrayUser::CreateDetailedView(user::LoginStatus status
) {
116 return new tray::AccountsDetailedView(this, status
);
119 void TrayUser::DestroyTrayView() {
125 void TrayUser::DestroyDefaultView() {
129 void TrayUser::DestroyDetailedView() {
132 void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status
) {
133 // Only the active user is represented in the tray.
136 if (GetTrayIndex() > 0)
138 bool need_label
= false;
139 bool need_avatar
= false;
141 case user::LOGGED_IN_LOCKED
:
142 case user::LOGGED_IN_USER
:
143 case user::LOGGED_IN_OWNER
:
144 case user::LOGGED_IN_PUBLIC
:
147 case user::LOGGED_IN_SUPERVISED
:
151 case user::LOGGED_IN_GUEST
:
154 case user::LOGGED_IN_RETAIL_MODE
:
155 case user::LOGGED_IN_KIOSK_APP
:
156 case user::LOGGED_IN_NONE
:
160 if ((need_avatar
!= (avatar_
!= NULL
)) ||
161 (need_label
!= (label_
!= NULL
))) {
162 layout_view_
->RemoveAllChildViews(true);
164 label_
= new views::Label
;
165 SetupLabelForTray(label_
);
166 layout_view_
->AddChildView(label_
);
171 avatar_
= new tray::RoundedImageView(kTrayAvatarCornerRadius
, true);
172 layout_view_
->AddChildView(avatar_
);
178 if (status
== user::LOGGED_IN_SUPERVISED
) {
180 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL
));
181 } else if (status
== user::LOGGED_IN_GUEST
) {
182 label_
->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL
));
186 avatar_
->SetCornerRadii(
187 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
, 0);
188 avatar_
->SetBorder(views::Border::NullBorder());
190 UpdateAvatarImage(status
);
192 // Update layout after setting label_ and avatar_ with new login status.
193 UpdateLayoutOfItem();
196 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment
) {
197 // Inactive users won't have a layout.
200 if (alignment
== SHELF_ALIGNMENT_BOTTOM
||
201 alignment
== SHELF_ALIGNMENT_TOP
) {
203 avatar_
->SetBorder(views::Border::NullBorder());
204 avatar_
->SetCornerRadii(
205 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
, 0);
208 // If label_ hasn't figured out its size yet, do that first.
209 if (label_
->GetContentsBounds().height() == 0)
210 label_
->SizeToPreferredSize();
211 int height
= label_
->GetContentsBounds().height();
212 int vertical_pad
= (kTrayItemSize
- height
) / 2;
213 int remainder
= height
% 2;
214 label_
->SetBorder(views::Border::CreateEmptyBorder(
215 vertical_pad
+ remainder
,
216 kTrayLabelItemHorizontalPaddingBottomAlignment
,
218 kTrayLabelItemHorizontalPaddingBottomAlignment
));
220 layout_view_
->SetLayoutManager(
221 new views::BoxLayout(views::BoxLayout::kHorizontal
,
222 0, 0, kUserLabelToIconPadding
));
225 avatar_
->SetBorder(views::Border::NullBorder());
226 avatar_
->SetCornerRadii(
227 0, 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
);
230 label_
->SetBorder(views::Border::CreateEmptyBorder(
231 kTrayLabelItemVerticalPaddingVerticalAlignment
,
232 kTrayLabelItemHorizontalPaddingBottomAlignment
,
233 kTrayLabelItemVerticalPaddingVerticalAlignment
,
234 kTrayLabelItemHorizontalPaddingBottomAlignment
));
236 layout_view_
->SetLayoutManager(
237 new views::BoxLayout(views::BoxLayout::kVertical
,
238 0, 0, kUserLabelToIconPadding
));
242 void TrayUser::OnUserUpdate() {
243 UpdateAvatarImage(Shell::GetInstance()->system_tray_delegate()->
244 GetUserLoginStatus());
247 void TrayUser::OnUserAddedToSession() {
248 SessionStateDelegate
* session_state_delegate
=
249 Shell::GetInstance()->session_state_delegate();
250 // Only create views for user items which are logged in.
251 if (GetTrayIndex() >= session_state_delegate
->NumberOfLoggedInUsers())
254 // Enforce a layout change that newly added items become visible.
255 UpdateLayoutOfItem();
257 // Update the user item.
259 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
262 void TrayUser::UpdateAvatarImage(user::LoginStatus status
) {
263 SessionStateDelegate
* session_state_delegate
=
264 Shell::GetInstance()->session_state_delegate();
266 GetTrayIndex() >= session_state_delegate
->NumberOfLoggedInUsers())
269 content::BrowserContext
* context
= session_state_delegate
->
270 GetBrowserContextByIndex(GetTrayIndex());
271 avatar_
->SetImage(session_state_delegate
->GetUserInfo(context
)->GetImage(),
272 gfx::Size(kTrayAvatarSize
, kTrayAvatarSize
));
274 // Unit tests might come here with no images for some users.
275 if (avatar_
->size().IsEmpty())
276 avatar_
->SetSize(gfx::Size(kTrayAvatarSize
, kTrayAvatarSize
));
279 MultiProfileIndex
TrayUser::GetTrayIndex() {
280 Shell
* shell
= Shell::GetInstance();
281 // If multi profile is not enabled we can use the normal index.
282 if (!shell
->delegate()->IsMultiProfilesEnabled())
283 return multiprofile_index_
;
284 // In case of multi profile we need to mirror the indices since the system
285 // tray items are in the reverse order then the menu items.
286 return shell
->session_state_delegate()->GetMaximumNumberOfLoggedInUsers() -
287 1 - multiprofile_index_
;
290 void TrayUser::UpdateLayoutOfItem() {
291 RootWindowController
* controller
= GetRootWindowController(
292 system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow());
293 if (controller
&& controller
->shelf()) {
294 UpdateAfterShelfAlignmentChange(
295 controller
->GetShelfLayoutManager()->GetAlignment());