• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ash/system/user/tray_user.h"
6 
7 #include "ash/ash_switches.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/session/session_state_delegate.h"
10 #include "ash/session/user_info.h"
11 #include "ash/shelf/shelf_layout_manager.h"
12 #include "ash/shell_delegate.h"
13 #include "ash/system/tray/system_tray.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 "grit/ash_strings.h"
24 #include "ui/aura/window.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/image/image.h"
27 #include "ui/views/border.h"
28 #include "ui/views/controls/label.h"
29 #include "ui/views/layout/box_layout.h"
30 #include "ui/views/view.h"
31 #include "ui/views/widget/widget.h"
32 
33 namespace {
34 
35 const int kUserLabelToIconPadding = 5;
36 
37 }  // namespace
38 
39 namespace ash {
40 
TrayUser(SystemTray * system_tray,MultiProfileIndex index)41 TrayUser::TrayUser(SystemTray* system_tray, MultiProfileIndex index)
42     : SystemTrayItem(system_tray),
43       multiprofile_index_(index),
44       user_(NULL),
45       layout_view_(NULL),
46       avatar_(NULL),
47       label_(NULL) {
48   Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this);
49 }
50 
~TrayUser()51 TrayUser::~TrayUser() {
52   Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this);
53 }
54 
GetStateForTest() const55 TrayUser::TestState TrayUser::GetStateForTest() const {
56   if (!user_)
57     return HIDDEN;
58   return user_->GetStateForTest();
59 }
60 
GetLayoutSizeForTest() const61 gfx::Size TrayUser::GetLayoutSizeForTest() const {
62   if (!layout_view_) {
63     return gfx::Size(0, 0);
64   } else {
65     return layout_view_->size();
66   }
67 }
68 
GetUserPanelBoundsInScreenForTest() const69 gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const {
70   DCHECK(user_);
71   return user_->GetBoundsInScreenOfUserButtonForTest();
72 }
73 
UpdateAfterLoginStatusChangeForTest(user::LoginStatus status)74 void TrayUser::UpdateAfterLoginStatusChangeForTest(user::LoginStatus status) {
75   UpdateAfterLoginStatusChange(status);
76 }
77 
CreateTrayView(user::LoginStatus status)78 views::View* TrayUser::CreateTrayView(user::LoginStatus status) {
79   CHECK(layout_view_ == NULL);
80 
81   layout_view_ = new views::View;
82   layout_view_->SetLayoutManager(
83       new views::BoxLayout(views::BoxLayout::kHorizontal,
84                            0, 0, kUserLabelToIconPadding));
85   UpdateAfterLoginStatusChange(status);
86   return layout_view_;
87 }
88 
CreateDefaultView(user::LoginStatus status)89 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
90   if (status == user::LOGGED_IN_NONE)
91     return NULL;
92   const SessionStateDelegate* session_state_delegate =
93       Shell::GetInstance()->session_state_delegate();
94 
95   // If the screen is locked show only the currently active user.
96   if (multiprofile_index_ && session_state_delegate->IsUserSessionBlocked())
97     return NULL;
98 
99   CHECK(user_ == NULL);
100 
101   int logged_in_users = session_state_delegate->NumberOfLoggedInUsers();
102 
103   // Do not show more UserView's then there are logged in users.
104   if (multiprofile_index_ >= logged_in_users)
105     return NULL;
106 
107   user_ = new tray::UserView(this, status, multiprofile_index_, false);
108   return user_;
109 }
110 
CreateDetailedView(user::LoginStatus status)111 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) {
112   return new tray::AccountsDetailedView(this, status);
113 }
114 
DestroyTrayView()115 void TrayUser::DestroyTrayView() {
116   layout_view_ = NULL;
117   avatar_ = NULL;
118   label_ = NULL;
119 }
120 
DestroyDefaultView()121 void TrayUser::DestroyDefaultView() {
122   user_ = NULL;
123 }
124 
DestroyDetailedView()125 void TrayUser::DestroyDetailedView() {
126 }
127 
UpdateAfterLoginStatusChange(user::LoginStatus status)128 void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) {
129   // Only the active user is represented in the tray.
130   if (!layout_view_)
131     return;
132   if (GetTrayIndex() > 0)
133     return;
134   bool need_label = false;
135   bool need_avatar = false;
136   switch (status) {
137     case user::LOGGED_IN_LOCKED:
138     case user::LOGGED_IN_USER:
139     case user::LOGGED_IN_OWNER:
140     case user::LOGGED_IN_PUBLIC:
141       need_avatar = true;
142       break;
143     case user::LOGGED_IN_LOCALLY_MANAGED:
144       need_avatar = true;
145       need_label = true;
146       break;
147     case user::LOGGED_IN_GUEST:
148       need_label = true;
149       break;
150     case user::LOGGED_IN_RETAIL_MODE:
151     case user::LOGGED_IN_KIOSK_APP:
152     case user::LOGGED_IN_NONE:
153       break;
154   }
155 
156   if ((need_avatar != (avatar_ != NULL)) ||
157       (need_label != (label_ != NULL))) {
158     layout_view_->RemoveAllChildViews(true);
159     if (need_label) {
160       label_ = new views::Label;
161       SetupLabelForTray(label_);
162       layout_view_->AddChildView(label_);
163     } else {
164       label_ = NULL;
165     }
166     if (need_avatar) {
167       avatar_ = new tray::RoundedImageView(kTrayAvatarCornerRadius, true);
168       layout_view_->AddChildView(avatar_);
169     } else {
170       avatar_ = NULL;
171     }
172   }
173 
174   if (status == user::LOGGED_IN_LOCALLY_MANAGED) {
175     label_->SetText(
176         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL));
177   } else if (status == user::LOGGED_IN_GUEST) {
178     label_->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL));
179   }
180 
181   if (avatar_) {
182     avatar_->SetCornerRadii(
183         0, kTrayAvatarCornerRadius, kTrayAvatarCornerRadius, 0);
184     avatar_->SetBorder(views::Border::NullBorder());
185   }
186   UpdateAvatarImage(status);
187 
188   // Update layout after setting label_ and avatar_ with new login status.
189   UpdateLayoutOfItem();
190 }
191 
UpdateAfterShelfAlignmentChange(ShelfAlignment alignment)192 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
193   // Inactive users won't have a layout.
194   if (!layout_view_)
195     return;
196   if (alignment == SHELF_ALIGNMENT_BOTTOM ||
197       alignment == SHELF_ALIGNMENT_TOP) {
198     if (avatar_) {
199       avatar_->SetBorder(views::Border::NullBorder());
200       avatar_->SetCornerRadii(
201           0, kTrayAvatarCornerRadius, kTrayAvatarCornerRadius, 0);
202     }
203     if (label_) {
204       // If label_ hasn't figured out its size yet, do that first.
205       if (label_->GetContentsBounds().height() == 0)
206         label_->SizeToPreferredSize();
207       int height = label_->GetContentsBounds().height();
208       int vertical_pad = (kTrayItemSize - height) / 2;
209       int remainder = height % 2;
210       label_->SetBorder(views::Border::CreateEmptyBorder(
211           vertical_pad + remainder,
212           kTrayLabelItemHorizontalPaddingBottomAlignment,
213           vertical_pad,
214           kTrayLabelItemHorizontalPaddingBottomAlignment));
215     }
216     layout_view_->SetLayoutManager(
217         new views::BoxLayout(views::BoxLayout::kHorizontal,
218                              0, 0, kUserLabelToIconPadding));
219   } else {
220     if (avatar_) {
221       avatar_->SetBorder(views::Border::NullBorder());
222       avatar_->SetCornerRadii(
223           0, 0, kTrayAvatarCornerRadius, kTrayAvatarCornerRadius);
224     }
225     if (label_) {
226       label_->SetBorder(views::Border::CreateEmptyBorder(
227           kTrayLabelItemVerticalPaddingVerticalAlignment,
228           kTrayLabelItemHorizontalPaddingBottomAlignment,
229           kTrayLabelItemVerticalPaddingVerticalAlignment,
230           kTrayLabelItemHorizontalPaddingBottomAlignment));
231     }
232     layout_view_->SetLayoutManager(
233         new views::BoxLayout(views::BoxLayout::kVertical,
234                              0, 0, kUserLabelToIconPadding));
235   }
236 }
237 
OnUserUpdate()238 void TrayUser::OnUserUpdate() {
239   UpdateAvatarImage(Shell::GetInstance()->system_tray_delegate()->
240       GetUserLoginStatus());
241 }
242 
OnUserAddedToSession()243 void TrayUser::OnUserAddedToSession() {
244   SessionStateDelegate* session_state_delegate =
245       Shell::GetInstance()->session_state_delegate();
246   // Only create views for user items which are logged in.
247   if (GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers())
248     return;
249 
250   // Enforce a layout change that newly added items become visible.
251   UpdateLayoutOfItem();
252 
253   // Update the user item.
254   UpdateAvatarImage(
255       Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
256 }
257 
UpdateAvatarImage(user::LoginStatus status)258 void TrayUser::UpdateAvatarImage(user::LoginStatus status) {
259   SessionStateDelegate* session_state_delegate =
260       Shell::GetInstance()->session_state_delegate();
261   if (!avatar_ ||
262       GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers())
263     return;
264 
265   content::BrowserContext* context = session_state_delegate->
266       GetBrowserContextByIndex(GetTrayIndex());
267   avatar_->SetImage(session_state_delegate->GetUserInfo(context)->GetImage(),
268                     gfx::Size(kTrayAvatarSize, kTrayAvatarSize));
269 
270   // Unit tests might come here with no images for some users.
271   if (avatar_->size().IsEmpty())
272     avatar_->SetSize(gfx::Size(kTrayAvatarSize, kTrayAvatarSize));
273 }
274 
GetTrayIndex()275 MultiProfileIndex TrayUser::GetTrayIndex() {
276   Shell* shell = Shell::GetInstance();
277   // If multi profile is not enabled we can use the normal index.
278   if (!shell->delegate()->IsMultiProfilesEnabled())
279     return multiprofile_index_;
280   // In case of multi profile we need to mirror the indices since the system
281   // tray items are in the reverse order then the menu items.
282   return shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers() -
283              1 - multiprofile_index_;
284 }
285 
UpdateLayoutOfItem()286 void TrayUser::UpdateLayoutOfItem() {
287   RootWindowController* controller = GetRootWindowController(
288       system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow());
289   if (controller && controller->shelf()) {
290     UpdateAfterShelfAlignmentChange(
291         controller->GetShelfLayoutManager()->GetAlignment());
292   }
293 }
294 
295 }  // namespace ash
296