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