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
),
46 layout_view_(nullptr),
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_
== nullptr);
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_
== nullptr);
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 std::string user_id
= Shell::GetInstance()
117 ->session_state_delegate()
120 tray::UserAccountsDelegate
* delegate
=
121 Shell::GetInstance()->system_tray_delegate()->GetUserAccountsDelegate(
125 return new tray::AccountsDetailedView(this, status
, delegate
);
128 void TrayUser::DestroyTrayView() {
129 layout_view_
= nullptr;
134 void TrayUser::DestroyDefaultView() {
138 void TrayUser::DestroyDetailedView() {
141 void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status
) {
142 // Only the active user is represented in the tray.
145 if (multiprofile_index_
> 0)
147 bool need_label
= false;
148 bool need_avatar
= false;
149 SystemTrayDelegate
* delegate
= Shell::GetInstance()->system_tray_delegate();
150 if (delegate
->IsUserSupervised())
153 case user::LOGGED_IN_LOCKED
:
154 case user::LOGGED_IN_USER
:
155 case user::LOGGED_IN_OWNER
:
156 case user::LOGGED_IN_PUBLIC
:
159 case user::LOGGED_IN_SUPERVISED
:
163 case user::LOGGED_IN_GUEST
:
166 case user::LOGGED_IN_KIOSK_APP
:
167 case user::LOGGED_IN_NONE
:
171 if ((need_avatar
!= (avatar_
!= nullptr)) ||
172 (need_label
!= (label_
!= nullptr))) {
173 layout_view_
->RemoveAllChildViews(true);
175 label_
= new views::Label
;
176 SetupLabelForTray(label_
);
177 layout_view_
->AddChildView(label_
);
182 avatar_
= new tray::RoundedImageView(kTrayAvatarCornerRadius
, true);
183 layout_view_
->AddChildView(avatar_
);
189 if (delegate
->IsUserSupervised()) {
191 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL
));
192 } else if (status
== user::LOGGED_IN_GUEST
) {
193 label_
->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL
));
197 avatar_
->SetCornerRadii(
198 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
, 0);
199 avatar_
->SetBorder(views::Border::NullBorder());
201 UpdateAvatarImage(status
);
203 // Update layout after setting label_ and avatar_ with new login status.
204 UpdateLayoutOfItem();
207 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment
) {
208 // Inactive users won't have a layout.
211 if (alignment
== SHELF_ALIGNMENT_BOTTOM
||
212 alignment
== SHELF_ALIGNMENT_TOP
) {
214 avatar_
->SetBorder(views::Border::NullBorder());
215 avatar_
->SetCornerRadii(
216 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
, 0);
219 // If label_ hasn't figured out its size yet, do that first.
220 if (label_
->GetContentsBounds().height() == 0)
221 label_
->SizeToPreferredSize();
222 int height
= label_
->GetContentsBounds().height();
223 int vertical_pad
= (kTrayItemSize
- height
) / 2;
224 int remainder
= height
% 2;
225 label_
->SetBorder(views::Border::CreateEmptyBorder(
226 vertical_pad
+ remainder
,
227 kTrayLabelItemHorizontalPaddingBottomAlignment
,
229 kTrayLabelItemHorizontalPaddingBottomAlignment
));
231 layout_view_
->SetLayoutManager(
232 new views::BoxLayout(views::BoxLayout::kHorizontal
,
233 0, 0, kUserLabelToIconPadding
));
236 avatar_
->SetBorder(views::Border::NullBorder());
237 avatar_
->SetCornerRadii(
238 0, 0, kTrayAvatarCornerRadius
, kTrayAvatarCornerRadius
);
241 label_
->SetBorder(views::Border::CreateEmptyBorder(
242 kTrayLabelItemVerticalPaddingVerticalAlignment
,
243 kTrayLabelItemHorizontalPaddingBottomAlignment
,
244 kTrayLabelItemVerticalPaddingVerticalAlignment
,
245 kTrayLabelItemHorizontalPaddingBottomAlignment
));
247 layout_view_
->SetLayoutManager(
248 new views::BoxLayout(views::BoxLayout::kVertical
,
249 0, 0, kUserLabelToIconPadding
));
253 void TrayUser::OnUserUpdate() {
254 UpdateAvatarImage(Shell::GetInstance()->system_tray_delegate()->
255 GetUserLoginStatus());
258 void TrayUser::OnUserAddedToSession() {
259 SessionStateDelegate
* session_state_delegate
=
260 Shell::GetInstance()->session_state_delegate();
261 // Only create views for user items which are logged in.
262 if (multiprofile_index_
>= session_state_delegate
->NumberOfLoggedInUsers())
265 // Enforce a layout change that newly added items become visible.
266 UpdateLayoutOfItem();
268 // Update the user item.
270 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
273 void TrayUser::UpdateAvatarImage(user::LoginStatus status
) {
274 SessionStateDelegate
* session_state_delegate
=
275 Shell::GetInstance()->session_state_delegate();
277 multiprofile_index_
>= session_state_delegate
->NumberOfLoggedInUsers())
280 const user_manager::UserInfo
* user_info
=
281 session_state_delegate
->GetUserInfo(multiprofile_index_
);
283 avatar_
->SetImage(user_info
->GetImage(),
284 gfx::Size(kTrayAvatarSize
, kTrayAvatarSize
));
286 // Unit tests might come here with no images for some users.
287 if (avatar_
->size().IsEmpty())
288 avatar_
->SetSize(gfx::Size(kTrayAvatarSize
, kTrayAvatarSize
));
291 void TrayUser::UpdateLayoutOfItem() {
292 RootWindowController
* controller
= GetRootWindowController(
293 system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow());
294 if (controller
&& controller
->shelf()) {
295 UpdateAfterShelfAlignmentChange(
296 controller
->GetShelfLayoutManager()->GetAlignment());