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 show only the currently active user.
97 if (multiprofile_index_
&& session_state_delegate
->IsUserSessionBlocked())
100 CHECK(user_
== NULL
);
102 int logged_in_users
= session_state_delegate
->NumberOfLoggedInUsers();
104 // Do not show more UserView's then there are logged in users.
105 if (multiprofile_index_
>= logged_in_users
)
108 user_
= new tray::UserView(this, status
, multiprofile_index_
, false);
112 views::View
* TrayUser::CreateDetailedView(user::LoginStatus status
) {
113 return new tray::AccountsDetailedView(this, status
);
116 void TrayUser::DestroyTrayView() {
122 void TrayUser::DestroyDefaultView() {
126 void TrayUser::DestroyDetailedView() {
129 void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status
) {
130 // Only the active user is represented in the tray.
133 if (GetTrayIndex() > 0)
135 bool need_label
= false;
136 bool need_avatar
= false;
138 case user::LOGGED_IN_LOCKED
:
139 case user::LOGGED_IN_USER
:
140 case user::LOGGED_IN_OWNER
:
141 case user::LOGGED_IN_PUBLIC
:
144 case user::LOGGED_IN_SUPERVISED
:
148 case user::LOGGED_IN_GUEST
:
151 case user::LOGGED_IN_RETAIL_MODE
:
152 case user::LOGGED_IN_KIOSK_APP
:
153 case user::LOGGED_IN_NONE
:
157 if ((need_avatar
!= (avatar_
!= NULL
)) ||
158 (need_label
!= (label_
!= NULL
))) {
159 layout_view_
->RemoveAllChildViews(true);
161 label_
= new views::Label
;
162 SetupLabelForTray(label_
);
163 layout_view_
->AddChildView(label_
);
168 avatar_
= new tray::RoundedImageView(kTrayAvatarCornerRadius
, true);
169 layout_view_
->AddChildView(avatar_
);
175 if (status
== user::LOGGED_IN_SUPERVISED
) {
177 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL
));
178 } else if (status
== user::LOGGED_IN_GUEST
) {
179 label_
->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL
));
183 avatar_
->SetCornerRadii(
184 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
, 0);
185 avatar_
->SetBorder(views::Border::NullBorder());
187 UpdateAvatarImage(status
);
189 // Update layout after setting label_ and avatar_ with new login status.
190 UpdateLayoutOfItem();
193 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment
) {
194 // Inactive users won't have a layout.
197 if (alignment
== SHELF_ALIGNMENT_BOTTOM
||
198 alignment
== SHELF_ALIGNMENT_TOP
) {
200 avatar_
->SetBorder(views::Border::NullBorder());
201 avatar_
->SetCornerRadii(
202 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
, 0);
205 // If label_ hasn't figured out its size yet, do that first.
206 if (label_
->GetContentsBounds().height() == 0)
207 label_
->SizeToPreferredSize();
208 int height
= label_
->GetContentsBounds().height();
209 int vertical_pad
= (kTrayItemSize
- height
) / 2;
210 int remainder
= height
% 2;
211 label_
->SetBorder(views::Border::CreateEmptyBorder(
212 vertical_pad
+ remainder
,
213 kTrayLabelItemHorizontalPaddingBottomAlignment
,
215 kTrayLabelItemHorizontalPaddingBottomAlignment
));
217 layout_view_
->SetLayoutManager(
218 new views::BoxLayout(views::BoxLayout::kHorizontal
,
219 0, 0, kUserLabelToIconPadding
));
222 avatar_
->SetBorder(views::Border::NullBorder());
223 avatar_
->SetCornerRadii(
224 0, 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
);
227 label_
->SetBorder(views::Border::CreateEmptyBorder(
228 kTrayLabelItemVerticalPaddingVerticalAlignment
,
229 kTrayLabelItemHorizontalPaddingBottomAlignment
,
230 kTrayLabelItemVerticalPaddingVerticalAlignment
,
231 kTrayLabelItemHorizontalPaddingBottomAlignment
));
233 layout_view_
->SetLayoutManager(
234 new views::BoxLayout(views::BoxLayout::kVertical
,
235 0, 0, kUserLabelToIconPadding
));
239 void TrayUser::OnUserUpdate() {
240 UpdateAvatarImage(Shell::GetInstance()->system_tray_delegate()->
241 GetUserLoginStatus());
244 void TrayUser::OnUserAddedToSession() {
245 SessionStateDelegate
* session_state_delegate
=
246 Shell::GetInstance()->session_state_delegate();
247 // Only create views for user items which are logged in.
248 if (GetTrayIndex() >= session_state_delegate
->NumberOfLoggedInUsers())
251 // Enforce a layout change that newly added items become visible.
252 UpdateLayoutOfItem();
254 // Update the user item.
256 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
259 void TrayUser::UpdateAvatarImage(user::LoginStatus status
) {
260 SessionStateDelegate
* session_state_delegate
=
261 Shell::GetInstance()->session_state_delegate();
263 GetTrayIndex() >= session_state_delegate
->NumberOfLoggedInUsers())
266 content::BrowserContext
* context
= session_state_delegate
->
267 GetBrowserContextByIndex(GetTrayIndex());
268 avatar_
->SetImage(session_state_delegate
->GetUserInfo(context
)->GetImage(),
269 gfx::Size(kTrayAvatarSize
, kTrayAvatarSize
));
271 // Unit tests might come here with no images for some users.
272 if (avatar_
->size().IsEmpty())
273 avatar_
->SetSize(gfx::Size(kTrayAvatarSize
, kTrayAvatarSize
));
276 MultiProfileIndex
TrayUser::GetTrayIndex() {
277 Shell
* shell
= Shell::GetInstance();
278 // If multi profile is not enabled we can use the normal index.
279 if (!shell
->delegate()->IsMultiProfilesEnabled())
280 return multiprofile_index_
;
281 // In case of multi profile we need to mirror the indices since the system
282 // tray items are in the reverse order then the menu items.
283 return shell
->session_state_delegate()->GetMaximumNumberOfLoggedInUsers() -
284 1 - multiprofile_index_
;
287 void TrayUser::UpdateLayoutOfItem() {
288 RootWindowController
* controller
= GetRootWindowController(
289 system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow());
290 if (controller
&& controller
->shelf()) {
291 UpdateAfterShelfAlignmentChange(
292 controller
->GetShelfLayoutManager()->GetAlignment());