tray_user.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/shell.h" 8#include "ash/system/tray/system_tray_delegate.h" 9#include "ash/system/tray/tray_constants.h" 10#include "ash/system/tray/tray_item_view.h" 11#include "ash/system/tray/tray_views.h" 12#include "base/utf_string_conversions.h" 13#include "grit/ash_strings.h" 14#include "skia/ext/image_operations.h" 15#include "third_party/skia/include/core/SkCanvas.h" 16#include "third_party/skia/include/core/SkPaint.h" 17#include "third_party/skia/include/core/SkPath.h" 18#include "ui/base/resource/resource_bundle.h" 19#include "ui/gfx/canvas.h" 20#include "ui/gfx/image/image.h" 21#include "ui/gfx/image/image_skia_operations.h" 22#include "ui/gfx/size.h" 23#include "ui/gfx/skia_util.h" 24#include "ui/views/controls/button/button.h" 25#include "ui/views/controls/button/text_button.h" 26#include "ui/views/controls/image_view.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 kUserInfoVerticalPadding = 10; 35const int kUserIconSize = 27; 36const int kProfileRoundedCornerRadius = 2; 37 38} // namespace 39 40namespace ash { 41namespace internal { 42 43namespace tray { 44 45// A custom image view with rounded edges. 46class RoundedImageView : public views::View { 47 public: 48 // Constructs a new rounded image view with rounded corners of radius 49 // |corner_radius|. 50 explicit RoundedImageView(int corner_radius) : corner_radius_(corner_radius) { 51 } 52 53 virtual ~RoundedImageView() { 54 } 55 56 // Set the image that should be displayed from a pointer. The pointer 57 // contents is copied in the receiver's image. 58 void SetImage(const gfx::ImageSkia& img, const gfx::Size& size) { 59 image_ = img; 60 image_size_ = size; 61 62 // Try to get the best image quality for the avatar. 63 resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_, 64 skia::ImageOperations::RESIZE_BEST, size); 65 if (GetWidget() && visible()) { 66 PreferredSizeChanged(); 67 SchedulePaint(); 68 } 69 } 70 71 // Overridden from views::View. 72 virtual gfx::Size GetPreferredSize() OVERRIDE { 73 return gfx::Size(image_size_.width() + GetInsets().width(), 74 image_size_.height() + GetInsets().height()); 75 } 76 77 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 78 View::OnPaint(canvas); 79 gfx::Rect image_bounds(size()); 80 image_bounds.ClampToCenteredSize(GetPreferredSize()); 81 image_bounds.Inset(GetInsets()); 82 const SkScalar kRadius = SkIntToScalar(corner_radius_); 83 SkPath path; 84 path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius); 85 SkPaint paint; 86 paint.setAntiAlias(true); 87 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); 88 canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(), 89 path, paint); 90 } 91 92 private: 93 gfx::ImageSkia image_; 94 gfx::ImageSkia resized_; 95 gfx::Size image_size_; 96 int corner_radius_; 97 98 DISALLOW_COPY_AND_ASSIGN(RoundedImageView); 99}; 100 101class UserView : public views::View, 102 public views::ButtonListener { 103 public: 104 explicit UserView(ash::user::LoginStatus login) 105 : login_(login), 106 container_(NULL), 107 user_info_(NULL), 108 username_(NULL), 109 email_(NULL), 110 signout_(NULL) { 111 CHECK(login_ != ash::user::LOGGED_IN_NONE); 112 set_background(views::Background::CreateSolidBackground(kBackgroundColor)); 113 114 bool guest = login_ == ash::user::LOGGED_IN_GUEST; 115 bool locked = login_ == ash::user::LOGGED_IN_LOCKED; 116 117 container_ = new TrayPopupTextButtonContainer; 118 container_->layout()->set_spread_blank_space(false); 119 AddChildView(container_); 120 121 if (!guest) 122 AddUserInfo(); 123 124 // A user should not be able to modify logged in state when screen is 125 // locked. 126 if (!locked) 127 AddButtonContainer(); 128 } 129 130 virtual ~UserView() {} 131 132 // Create container for buttons. 133 void AddButtonContainer() { 134 TrayPopupTextButton* button = new TrayPopupTextButton(this, 135 ash::user::GetLocalizedSignOutStringForStatus(login_)); 136 container_->AddTextButton(button); 137 signout_ = button; 138 } 139 140 private: 141 void AddUserInfo() { 142 user_info_ = new views::View; 143 user_info_->SetLayoutManager(new views::BoxLayout( 144 views::BoxLayout::kHorizontal, kTrayPopupPaddingHorizontal, 145 kUserInfoVerticalPadding, kTrayPopupPaddingBetweenItems)); 146 container_->AddChildView(user_info_); 147 148 if (login_ == ash::user::LOGGED_IN_KIOSK) { 149 views::Label* label = new views::Label; 150 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 151 label->SetText( 152 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL)); 153 label->set_border(views::Border::CreateEmptyBorder( 154 0, 4, 0, 1)); 155 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 156 user_info_->AddChildView(label); 157 return; 158 } 159 160 RoundedImageView* image = new RoundedImageView(kProfileRoundedCornerRadius); 161 image->SetImage(ash::Shell::GetInstance()->tray_delegate()->GetUserImage(), 162 gfx::Size(kUserIconSize, kUserIconSize)); 163 user_info_->AddChildView(image); 164 165 views::View* user = new views::View; 166 user->SetLayoutManager(new views::BoxLayout( 167 views::BoxLayout::kVertical, 0, 5, 0)); 168 ash::SystemTrayDelegate* tray = 169 ash::Shell::GetInstance()->tray_delegate(); 170 username_ = new views::Label(tray->GetUserDisplayName()); 171 username_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 172 user->AddChildView(username_); 173 174 email_ = new views::Label(UTF8ToUTF16(tray->GetUserEmail())); 175 email_->SetFont(username_->font().DeriveFont(-1)); 176 email_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 177 email_->SetEnabled(false); 178 user->AddChildView(email_); 179 180 user_info_->AddChildView(user); 181 } 182 183 // Overridden from views::ButtonListener. 184 virtual void ButtonPressed(views::Button* sender, 185 const ui::Event& event) OVERRIDE { 186 CHECK(sender == signout_); 187 ash::SystemTrayDelegate* tray = ash::Shell::GetInstance()->tray_delegate(); 188 tray->SignOut(); 189 } 190 191 // Overridden from views::View. 192 virtual gfx::Size GetPreferredSize() OVERRIDE { 193 gfx::Size size; 194 if (user_info_) 195 size = user_info_->GetPreferredSize(); 196 if (signout_) { 197 gfx::Size signout_size = signout_->GetPreferredSize(); 198 // Make sure the user default view item at least as tall as the other 199 // tray popup items. 200 if (size.height() == 0) 201 size.set_height(kTrayPopupItemHeight); 202 size.set_height(std::max(size.height(), signout_size.height())); 203 size.set_width(size.width() + signout_size.width() + 204 kTrayPopupPaddingHorizontal * 2 + kTrayPopupPaddingBetweenItems); 205 } 206 return size; 207 } 208 209 virtual void Layout() OVERRIDE { 210 views::View::Layout(); 211 if (bounds().IsEmpty()) 212 return; 213 214 container_->SetBoundsRect(gfx::Rect(size())); 215 if (signout_ && user_info_) { 216 gfx::Rect signout_bounds(bounds()); 217 signout_bounds.ClampToCenteredSize(signout_->GetPreferredSize()); 218 signout_bounds.set_x(width() - signout_bounds.width() - 219 kTrayPopupPaddingHorizontal); 220 signout_->SetBoundsRect(signout_bounds); 221 222 gfx::Rect usercard_bounds(user_info_->GetPreferredSize()); 223 usercard_bounds.set_width(signout_bounds.x()); 224 user_info_->SetBoundsRect(usercard_bounds); 225 } else if (signout_) { 226 signout_->SetBoundsRect(gfx::Rect(size())); 227 } else if (user_info_) { 228 user_info_->SetBoundsRect(gfx::Rect(size())); 229 } 230 } 231 232 user::LoginStatus login_; 233 234 TrayPopupTextButtonContainer* container_; 235 views::View* user_info_; 236 views::Label* username_; 237 views::Label* email_; 238 239 views::Button* signout_; 240 241 DISALLOW_COPY_AND_ASSIGN(UserView); 242}; 243 244} // namespace tray 245 246TrayUser::TrayUser() 247 : user_(NULL), 248 avatar_(NULL), 249 label_(NULL) { 250} 251 252TrayUser::~TrayUser() { 253} 254 255views::View* TrayUser::CreateTrayView(user::LoginStatus status) { 256 CHECK(avatar_ == NULL); 257 CHECK(label_ == NULL); 258 if (status == user::LOGGED_IN_GUEST) { 259 label_ = new views::Label; 260 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 261 label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL)); 262 SetupLabelForTray(label_); 263 } else { 264 avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius); 265 } 266 UpdateAfterLoginStatusChange(status); 267 return avatar_ ? static_cast<views::View*>(avatar_) 268 : static_cast<views::View*>(label_); 269} 270 271views::View* TrayUser::CreateDefaultView(user::LoginStatus status) { 272 if (status == user::LOGGED_IN_NONE) 273 return NULL; 274 275 CHECK(user_ == NULL); 276 user_ = new tray::UserView(status); 277 return user_; 278} 279 280views::View* TrayUser::CreateDetailedView(user::LoginStatus status) { 281 return NULL; 282} 283 284void TrayUser::DestroyTrayView() { 285 avatar_ = NULL; 286 label_ = NULL; 287} 288 289void TrayUser::DestroyDefaultView() { 290 user_ = NULL; 291} 292 293void TrayUser::DestroyDetailedView() { 294} 295 296void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) { 297 switch (status) { 298 case user::LOGGED_IN_LOCKED: 299 case user::LOGGED_IN_USER: 300 case user::LOGGED_IN_OWNER: 301 case user::LOGGED_IN_PUBLIC: 302 avatar_->SetImage( 303 ash::Shell::GetInstance()->tray_delegate()->GetUserImage(), 304 gfx::Size(kUserIconSize, kUserIconSize)); 305 avatar_->SetVisible(true); 306 break; 307 308 case user::LOGGED_IN_GUEST: 309 label_->SetVisible(true); 310 break; 311 312 case user::LOGGED_IN_KIOSK: 313 case user::LOGGED_IN_NONE: 314 avatar_->SetVisible(false); 315 break; 316 } 317} 318 319void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 320 if (avatar_) { 321 if (alignment == SHELF_ALIGNMENT_BOTTOM) { 322 avatar_->set_border(views::Border::CreateEmptyBorder( 323 0, kTrayImageItemHorizontalPaddingBottomAlignment + 2, 324 0, kTrayImageItemHorizontalPaddingBottomAlignment)); 325 } else { 326 SetTrayImageItemBorder(avatar_, alignment); 327 } 328 } else { 329 if (alignment == SHELF_ALIGNMENT_BOTTOM) { 330 label_->set_border(views::Border::CreateEmptyBorder( 331 0, kTrayLabelItemHorizontalPaddingBottomAlignment, 332 0, kTrayLabelItemHorizontalPaddingBottomAlignment)); 333 } else { 334 label_->set_border(views::Border::CreateEmptyBorder( 335 kTrayLabelItemVerticalPaddingVeriticalAlignment, 336 kTrayLabelItemHorizontalPaddingBottomAlignment, 337 kTrayLabelItemVerticalPaddingVeriticalAlignment, 338 kTrayLabelItemHorizontalPaddingBottomAlignment)); 339 } 340 } 341} 342 343void TrayUser::OnUserUpdate() { 344 // Check for null to avoid crbug.com/150944. 345 if (avatar_) { 346 avatar_->SetImage( 347 ash::Shell::GetInstance()->tray_delegate()->GetUserImage(), 348 gfx::Size(kUserIconSize, kUserIconSize)); 349 } 350} 351 352} // namespace internal 353} // namespace ash 354