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