tray_user.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 <algorithm> 8#include <climits> 9#include <vector> 10 11#include "ash/shell.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_views.h" 18#include "base/i18n/rtl.h" 19#include "base/logging.h" 20#include "base/memory/scoped_vector.h" 21#include "base/string16.h" 22#include "base/string_util.h" 23#include "base/utf_string_conversions.h" 24#include "grit/ash_resources.h" 25#include "grit/ash_strings.h" 26#include "skia/ext/image_operations.h" 27#include "third_party/skia/include/core/SkCanvas.h" 28#include "third_party/skia/include/core/SkPaint.h" 29#include "third_party/skia/include/core/SkPath.h" 30#include "ui/base/l10n/l10n_util.h" 31#include "ui/base/range/range.h" 32#include "ui/base/resource/resource_bundle.h" 33#include "ui/base/text/text_elider.h" 34#include "ui/gfx/canvas.h" 35#include "ui/gfx/font.h" 36#include "ui/gfx/image/image.h" 37#include "ui/gfx/image/image_skia_operations.h" 38#include "ui/gfx/insets.h" 39#include "ui/gfx/rect.h" 40#include "ui/gfx/render_text.h" 41#include "ui/gfx/size.h" 42#include "ui/gfx/skia_util.h" 43#include "ui/views/border.h" 44#include "ui/views/bubble/tray_bubble_view.h" 45#include "ui/views/controls/button/button.h" 46#include "ui/views/controls/button/custom_button.h" 47#include "ui/views/controls/image_view.h" 48#include "ui/views/controls/label.h" 49#include "ui/views/controls/link.h" 50#include "ui/views/controls/link_listener.h" 51#include "ui/views/layout/box_layout.h" 52#include "ui/views/layout/fill_layout.h" 53#include "ui/views/painter.h" 54#include "ui/views/view.h" 55#include "ui/views/widget/widget.h" 56 57namespace { 58 59const int kUserDetailsVerticalPadding = 5; 60const int kUserCardVerticalPadding = 10; 61const int kProfileRoundedCornerRadius = 2; 62const int kUserIconSize = 27; 63 64// The invisible word joiner character, used as a marker to indicate the start 65// and end of the user's display name in the public account user card's text. 66const char16 kDisplayNameMark[] = { 0x2060, 0 }; 67 68const int kPublicAccountLogoutButtonBorderImagesNormal[] = { 69 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 70 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 71 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 72 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 73 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 74 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 75 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 76 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 77 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 78}; 79 80const int kPublicAccountLogoutButtonBorderImagesHovered[] = { 81 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 82 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 83 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 84 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 85 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND, 86 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 87 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 88 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 89 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 90}; 91 92} // namespace 93 94namespace ash { 95namespace internal { 96 97namespace tray { 98 99// A custom image view with rounded edges. 100class RoundedImageView : public views::View { 101 public: 102 // Constructs a new rounded image view with rounded corners of radius 103 // |corner_radius|. 104 explicit RoundedImageView(int corner_radius); 105 virtual ~RoundedImageView(); 106 107 // Set the image that should be displayed. The image contents is copied to the 108 // receiver's image. 109 void SetImage(const gfx::ImageSkia& img, const gfx::Size& size); 110 111 private: 112 // Overridden from views::View. 113 virtual gfx::Size GetPreferredSize() OVERRIDE; 114 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 115 116 gfx::ImageSkia image_; 117 gfx::ImageSkia resized_; 118 gfx::Size image_size_; 119 int corner_radius_; 120 121 DISALLOW_COPY_AND_ASSIGN(RoundedImageView); 122}; 123 124class ClickableAvatar : public views::CustomButton { 125 public: 126 explicit ClickableAvatar(views::ButtonListener* listener); 127 virtual ~ClickableAvatar(); 128 129 private: 130 DISALLOW_COPY_AND_ASSIGN(ClickableAvatar); 131}; 132 133// The user details shown in public account mode. This is essentially a label 134// but with custom painting code as the text is styled with multiple colors and 135// contains a link. 136class PublicAccountUserDetails : public views::View, 137 public views::LinkListener { 138 public: 139 PublicAccountUserDetails(SystemTrayItem* owner, int used_width); 140 virtual ~PublicAccountUserDetails(); 141 142 private: 143 // Overridden from views::View. 144 virtual void Layout() OVERRIDE; 145 virtual gfx::Size GetPreferredSize() OVERRIDE; 146 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 147 148 // Overridden from views::LinkListener. 149 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; 150 151 // Calculate a preferred size that ensures the label text and the following 152 // link do not wrap over more than three lines in total for aesthetic reasons 153 // if possible. 154 void CalculatePreferredSize(SystemTrayItem* owner, int used_width); 155 156 string16 text_; 157 views::Link* learn_more_; 158 gfx::Size preferred_size_; 159 ScopedVector<gfx::RenderText> lines_; 160 161 DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails); 162}; 163 164class UserView : public views::View, 165 public views::ButtonListener { 166 public: 167 explicit UserView(SystemTrayItem* owner, ash::user::LoginStatus login); 168 virtual ~UserView(); 169 170 private: 171 // Overridden from views::View. 172 virtual gfx::Size GetPreferredSize() OVERRIDE; 173 virtual void Layout() OVERRIDE; 174 175 // Overridden from views::ButtonListener. 176 virtual void ButtonPressed(views::Button* sender, 177 const ui::Event& event) OVERRIDE; 178 179 void AddLogoutButton(ash::user::LoginStatus login); 180 void AddUserCard(SystemTrayItem* owner, ash::user::LoginStatus login); 181 182 views::View* user_card_; 183 views::View* logout_button_; 184 ClickableAvatar* profile_picture_; 185 186 DISALLOW_COPY_AND_ASSIGN(UserView); 187}; 188 189RoundedImageView::RoundedImageView(int corner_radius) 190 : corner_radius_(corner_radius) {} 191 192RoundedImageView::~RoundedImageView() {} 193 194void RoundedImageView::SetImage(const gfx::ImageSkia& img, 195 const gfx::Size& size) { 196 image_ = img; 197 image_size_ = size; 198 199 // Try to get the best image quality for the avatar. 200 resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_, 201 skia::ImageOperations::RESIZE_BEST, size); 202 if (GetWidget() && visible()) { 203 PreferredSizeChanged(); 204 SchedulePaint(); 205 } 206} 207 208gfx::Size RoundedImageView::GetPreferredSize() { 209 return gfx::Size(image_size_.width() + GetInsets().width(), 210 image_size_.height() + GetInsets().height()); 211} 212 213void RoundedImageView::OnPaint(gfx::Canvas* canvas) { 214 View::OnPaint(canvas); 215 gfx::Rect image_bounds(size()); 216 image_bounds.ClampToCenteredSize(GetPreferredSize()); 217 image_bounds.Inset(GetInsets()); 218 const SkScalar kRadius = SkIntToScalar(corner_radius_); 219 SkPath path; 220 path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius); 221 SkPaint paint; 222 paint.setAntiAlias(true); 223 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); 224 canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(), 225 path, paint); 226} 227 228ClickableAvatar::ClickableAvatar(views::ButtonListener* listener) 229 : views::CustomButton(listener) { 230 SetLayoutManager(new views::FillLayout()); 231 RoundedImageView* user_picture = 232 new RoundedImageView(kProfileRoundedCornerRadius); 233 user_picture->SetImage( 234 ash::Shell::GetInstance()->system_tray_delegate()->GetUserImage(), 235 gfx::Size(kUserIconSize, kUserIconSize)); 236 AddChildView(user_picture); 237} 238 239ClickableAvatar::~ClickableAvatar() {} 240 241PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner, 242 int used_width) 243 : learn_more_(NULL) { 244 const int inner_padding = 245 kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems; 246 const bool rtl = base::i18n::IsRTL(); 247 set_border(views::Border::CreateEmptyBorder( 248 kUserDetailsVerticalPadding, rtl ? 0 : inner_padding, 249 kUserDetailsVerticalPadding, rtl ? inner_padding : 0)); 250 251 ash::SystemTrayDelegate* delegate = 252 ash::Shell::GetInstance()->system_tray_delegate(); 253 // Retrieve the user's display name and wrap it with markers. 254 string16 display_name = delegate->GetUserDisplayName(); 255 RemoveChars(display_name, kDisplayNameMark, &display_name); 256 display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0]; 257 // Retrieve the domain managing the device and wrap it with markers. 258 string16 domain = UTF8ToUTF16(delegate->GetEnterpriseDomain()); 259 RemoveChars(domain, kDisplayNameMark, &domain); 260 base::i18n::WrapStringWithLTRFormatting(&domain); 261 // Retrieve the label text, inserting the display name and domain. 262 text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL, 263 display_name, domain); 264 265 learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE)); 266 learn_more_->SetUnderline(false); 267 learn_more_->set_listener(this); 268 AddChildView(learn_more_); 269 270 CalculatePreferredSize(owner, used_width); 271} 272 273PublicAccountUserDetails::~PublicAccountUserDetails() {} 274 275void PublicAccountUserDetails::Layout() { 276 lines_.clear(); 277 const gfx::Rect contents_area = GetContentsBounds(); 278 if (contents_area.IsEmpty()) 279 return; 280 281 // Word-wrap the label text. 282 const gfx::Font font; 283 std::vector<string16> lines; 284 ui::ElideRectangleText(text_, font, contents_area.width(), 285 contents_area.height(), ui::ELIDE_LONG_WORDS, &lines); 286 // Loop through the lines, creating a renderer for each. 287 gfx::Point position = contents_area.origin(); 288 ui::Range display_name(ui::Range::InvalidRange()); 289 for (std::vector<string16>::const_iterator it = lines.begin(); 290 it != lines.end(); ++it) { 291 gfx::RenderText* line = gfx::RenderText::CreateInstance(); 292 line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI); 293 line->SetText(*it); 294 const gfx::Size size(contents_area.width(), line->GetStringSize().height()); 295 line->SetDisplayRect(gfx::Rect(position, size)); 296 position.set_y(position.y() + size.height()); 297 298 // Set the default text color for the line. 299 line->SetColor(kPublicAccountUserCardTextColor); 300 301 // If a range of the line contains the user's display name, apply a custom 302 // text color to it. 303 if (display_name.is_empty()) 304 display_name.set_start(it->find(kDisplayNameMark)); 305 if (!display_name.is_empty()) { 306 display_name.set_end( 307 it->find(kDisplayNameMark, display_name.start() + 1)); 308 ui::Range line_range(0, it->size()); 309 line->ApplyColor(kPublicAccountUserCardNameColor, 310 display_name.Intersect(line_range)); 311 // Update the range for the next line. 312 if (display_name.end() >= line_range.end()) 313 display_name.set_start(0); 314 else 315 display_name = ui::Range::InvalidRange(); 316 } 317 318 lines_.push_back(line); 319 } 320 321 // Position the link after the label text, separated by a space. If it does 322 // not fit onto the last line of the text, wrap the link onto its own line. 323 const gfx::Size last_line_size = lines_.back()->GetStringSize(); 324 const int space_width = font.GetStringWidth(ASCIIToUTF16(" ")); 325 const gfx::Size link_size = learn_more_->GetPreferredSize(); 326 if (contents_area.width() - last_line_size.width() >= 327 space_width + link_size.width()) { 328 position.set_x(position.x() + last_line_size.width() + space_width); 329 position.set_y(position.y() - last_line_size.height()); 330 } 331 position.set_y(position.y() - learn_more_->GetInsets().top()); 332 gfx::Rect learn_more_bounds(position, link_size); 333 learn_more_bounds.Intersect(contents_area); 334 if (base::i18n::IsRTL()) { 335 const gfx::Insets insets = GetInsets(); 336 learn_more_bounds.Offset(insets.right() - insets.left(), 0); 337 } 338 learn_more_->SetBoundsRect(learn_more_bounds); 339} 340 341gfx::Size PublicAccountUserDetails::GetPreferredSize() { 342 return preferred_size_; 343} 344 345void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) { 346 for (ScopedVector<gfx::RenderText>::const_iterator it = lines_.begin(); 347 it != lines_.end(); ++it) { 348 (*it)->Draw(canvas); 349 } 350 views::View::OnPaint(canvas); 351} 352 353void PublicAccountUserDetails::LinkClicked(views::Link* source, 354 int event_flags) { 355 DCHECK_EQ(source, learn_more_); 356 ash::Shell::GetInstance()->system_tray_delegate()->ShowPublicAccountInfo(); 357} 358 359void PublicAccountUserDetails::CalculatePreferredSize(SystemTrayItem* owner, 360 int used_width) { 361 const gfx::Font font; 362 const gfx::Size link_size = learn_more_->GetPreferredSize(); 363 const int space_width = font.GetStringWidth(ASCIIToUTF16(" ")); 364 const gfx::Insets insets = GetInsets(); 365 views::TrayBubbleView* bubble_view = 366 owner->system_tray()->GetSystemBubble()->bubble_view(); 367 int min_width = std::max( 368 link_size.width(), 369 bubble_view->GetPreferredSize().width() - (used_width + insets.width())); 370 int max_width = std::min( 371 font.GetStringWidth(text_) + space_width + link_size.width(), 372 bubble_view->GetMaximumSize().width() - (used_width + insets.width())); 373 // Do a binary search for the minimum width that ensures no more than three 374 // lines are needed. The lower bound is the minimum of the current bubble 375 // width and the width of the link (as no wrapping is permitted inside the 376 // link). The upper bound is the maximum of the largest allowed bubble width 377 // and the sum of the label text and link widths when put on a single line. 378 std::vector<string16> lines; 379 while (min_width < max_width) { 380 lines.clear(); 381 const int width = (min_width + max_width) / 2; 382 const bool too_narrow = ui::ElideRectangleText( 383 text_, font, width, INT_MAX, ui::TRUNCATE_LONG_WORDS, &lines) != 0; 384 int line_count = lines.size(); 385 if (!too_narrow && line_count == 3 && 386 width - font.GetStringWidth(lines.back()) <= 387 space_width + link_size.width()) { 388 ++line_count; 389 } 390 if (too_narrow || line_count > 3) 391 min_width = width + 1; 392 else 393 max_width = width; 394 } 395 396 // Calculate the corresponding height and set the preferred size. 397 lines.clear(); 398 ui::ElideRectangleText( 399 text_, font, min_width, INT_MAX, ui::TRUNCATE_LONG_WORDS, &lines); 400 int line_count = lines.size(); 401 if (min_width - font.GetStringWidth(lines.back()) <= 402 space_width + link_size.width()) { 403 ++line_count; 404 } 405 const int line_height = font.GetHeight(); 406 const int link_extra_height = std::max( 407 link_size.height() - learn_more_->GetInsets().top() - line_height, 0); 408 preferred_size_ = gfx::Size( 409 min_width + insets.width(), 410 line_count * line_height + link_extra_height + insets.height()); 411 412 bubble_view->SetWidth(preferred_size_.width() + used_width); 413} 414 415UserView::UserView(SystemTrayItem* owner, ash::user::LoginStatus login) 416 : user_card_(NULL), 417 logout_button_(NULL), 418 profile_picture_(NULL) { 419 CHECK_NE(ash::user::LOGGED_IN_NONE, login); 420 set_background(views::Background::CreateSolidBackground( 421 login == ash::user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor : 422 kBackgroundColor)); 423 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 424 kTrayPopupPaddingBetweenItems)); 425 // The logout button must be added before the user card so that the user card 426 // can correctly calculate the remaining available width. 427 AddLogoutButton(login); 428 AddUserCard(owner, login); 429} 430 431UserView::~UserView() {} 432 433gfx::Size UserView::GetPreferredSize() { 434 gfx::Size size = views::View::GetPreferredSize(); 435 if (!user_card_) { 436 // Make sure the default user view item is at least as tall as the other 437 // items. 438 size.set_height(std::max(size.height(), 439 kTrayPopupItemHeight + GetInsets().height())); 440 } 441 return size; 442} 443 444void UserView::Layout() { 445 gfx::Rect contents_area(GetContentsBounds()); 446 if (user_card_ && logout_button_) { 447 // Give the logout button the space it requests. 448 gfx::Rect logout_area = contents_area; 449 logout_area.ClampToCenteredSize(logout_button_->GetPreferredSize()); 450 logout_area.set_x(contents_area.right() - logout_area.width()); 451 logout_button_->SetBoundsRect(logout_area); 452 453 // Give the remaining space to the user card. 454 gfx::Rect user_card_area = contents_area; 455 int remaining_width = contents_area.width() - 456 (logout_area.width() + kTrayPopupPaddingBetweenItems); 457 user_card_area.set_width(std::max(0, remaining_width)); 458 user_card_->SetBoundsRect(user_card_area); 459 } else if (user_card_) { 460 user_card_->SetBoundsRect(contents_area); 461 } else if (logout_button_) { 462 logout_button_->SetBoundsRect(contents_area); 463 } 464} 465 466void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) { 467 if (sender == logout_button_) 468 ash::Shell::GetInstance()->system_tray_delegate()->SignOut(); 469 else if (sender == profile_picture_) 470 ash::Shell::GetInstance()->system_tray_delegate()->ChangeProfilePicture(); 471 else 472 NOTREACHED(); 473} 474 475void UserView::AddLogoutButton(ash::user::LoginStatus login) { 476 // A user should not be able to modify logged-in state when screen is 477 // locked. 478 if (login == ash::user::LOGGED_IN_LOCKED) 479 return; 480 481 const string16 title = ash::user::GetLocalizedSignOutStringForStatus(login, 482 true); 483 TrayPopupLabelButton* logout_button = new TrayPopupLabelButton(this, title); 484 logout_button->SetAccessibleName(title); 485 logout_button_ = logout_button; 486 // In public account mode, the logout button border has a custom color. 487 if (login == ash::user::LOGGED_IN_PUBLIC) { 488 TrayPopupLabelButtonBorder* border = 489 static_cast<TrayPopupLabelButtonBorder*>(logout_button_->border()); 490 border->SetPainter(false, views::Button::STATE_NORMAL, 491 views::Painter::CreateImageGridPainter( 492 kPublicAccountLogoutButtonBorderImagesNormal)); 493 border->SetPainter(false, views::Button::STATE_HOVERED, 494 views::Painter::CreateImageGridPainter( 495 kPublicAccountLogoutButtonBorderImagesHovered)); 496 border->SetPainter(false, views::Button::STATE_PRESSED, 497 views::Painter::CreateImageGridPainter( 498 kPublicAccountLogoutButtonBorderImagesHovered)); 499 } 500 AddChildView(logout_button_); 501} 502 503void UserView::AddUserCard(SystemTrayItem* owner, 504 ash::user::LoginStatus login) { 505 if (login == ash::user::LOGGED_IN_GUEST) 506 return; 507 508 set_border(views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 509 0, kTrayPopupPaddingHorizontal)); 510 511 user_card_ = new views::View(); 512 user_card_->SetLayoutManager(new views::BoxLayout( 513 views::BoxLayout::kHorizontal, 0, kUserCardVerticalPadding, 514 kTrayPopupPaddingBetweenItems)); 515 AddChildViewAt(user_card_, 0); 516 517 if (login == ash::user::LOGGED_IN_RETAIL_MODE) { 518 views::Label* details = new views::Label; 519 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 520 details->SetText( 521 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL)); 522 details->set_border(views::Border::CreateEmptyBorder(0, 4, 0, 1)); 523 details->SetHorizontalAlignment(gfx::ALIGN_LEFT); 524 user_card_->AddChildView(details); 525 return; 526 } 527 profile_picture_ = new ClickableAvatar(this); 528 user_card_->AddChildView(profile_picture_); 529 530 if (login == ash::user::LOGGED_IN_PUBLIC) { 531 user_card_->AddChildView(new PublicAccountUserDetails( 532 owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems)); 533 return; 534 } 535 536 ash::SystemTrayDelegate* delegate = 537 ash::Shell::GetInstance()->system_tray_delegate(); 538 views::View* details = new views::View; 539 details->SetLayoutManager(new views::BoxLayout( 540 views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0)); 541 views::Label* username = new views::Label(delegate->GetUserDisplayName()); 542 username->SetHorizontalAlignment(gfx::ALIGN_LEFT); 543 details->AddChildView(username); 544 545 views::Label* email = new views::Label(UTF8ToUTF16(delegate->GetUserEmail())); 546 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 547 email->SetFont(bundle.GetFont(ui::ResourceBundle::SmallFont)); 548 email->SetHorizontalAlignment(gfx::ALIGN_LEFT); 549 email->SetEnabled(false); 550 details->AddChildView(email); 551 user_card_->AddChildView(details); 552} 553 554} // namespace tray 555 556TrayUser::TrayUser(SystemTray* system_tray) 557 : SystemTrayItem(system_tray), 558 user_(NULL), 559 avatar_(NULL), 560 label_(NULL) { 561 Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this); 562} 563 564TrayUser::~TrayUser() { 565 Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this); 566} 567 568views::View* TrayUser::CreateTrayView(user::LoginStatus status) { 569 CHECK(avatar_ == NULL); 570 CHECK(label_ == NULL); 571 if (status == user::LOGGED_IN_GUEST) { 572 label_ = new views::Label; 573 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 574 label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL)); 575 SetupLabelForTray(label_); 576 } else { 577 avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius); 578 } 579 UpdateAfterLoginStatusChange(status); 580 return avatar_ ? static_cast<views::View*>(avatar_) 581 : static_cast<views::View*>(label_); 582} 583 584views::View* TrayUser::CreateDefaultView(user::LoginStatus status) { 585 if (status == user::LOGGED_IN_NONE) 586 return NULL; 587 588 CHECK(user_ == NULL); 589 user_ = new tray::UserView(this, status); 590 return user_; 591} 592 593views::View* TrayUser::CreateDetailedView(user::LoginStatus status) { 594 return NULL; 595} 596 597void TrayUser::DestroyTrayView() { 598 avatar_ = NULL; 599 label_ = NULL; 600} 601 602void TrayUser::DestroyDefaultView() { 603 user_ = NULL; 604} 605 606void TrayUser::DestroyDetailedView() { 607} 608 609void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) { 610 switch (status) { 611 case user::LOGGED_IN_LOCKED: 612 case user::LOGGED_IN_USER: 613 case user::LOGGED_IN_OWNER: 614 case user::LOGGED_IN_PUBLIC: 615 case user::LOGGED_IN_LOCALLY_MANAGED: 616 avatar_->SetImage( 617 ash::Shell::GetInstance()->system_tray_delegate()->GetUserImage(), 618 gfx::Size(kUserIconSize, kUserIconSize)); 619 avatar_->SetVisible(true); 620 break; 621 622 case user::LOGGED_IN_GUEST: 623 label_->SetVisible(true); 624 break; 625 626 case user::LOGGED_IN_RETAIL_MODE: 627 case user::LOGGED_IN_KIOSK_APP: 628 case user::LOGGED_IN_NONE: 629 avatar_->SetVisible(false); 630 break; 631 } 632} 633 634void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 635 if (avatar_) { 636 if (alignment == SHELF_ALIGNMENT_BOTTOM || 637 alignment == SHELF_ALIGNMENT_TOP) { 638 avatar_->set_border(views::Border::CreateEmptyBorder( 639 0, kTrayImageItemHorizontalPaddingBottomAlignment + 2, 640 0, kTrayImageItemHorizontalPaddingBottomAlignment)); 641 } else { 642 SetTrayImageItemBorder(avatar_, alignment); 643 } 644 } else { 645 if (alignment == SHELF_ALIGNMENT_BOTTOM || 646 alignment == SHELF_ALIGNMENT_TOP) { 647 label_->set_border(views::Border::CreateEmptyBorder( 648 0, kTrayLabelItemHorizontalPaddingBottomAlignment, 649 0, kTrayLabelItemHorizontalPaddingBottomAlignment)); 650 } else { 651 label_->set_border(views::Border::CreateEmptyBorder( 652 kTrayLabelItemVerticalPaddingVeriticalAlignment, 653 kTrayLabelItemHorizontalPaddingBottomAlignment, 654 kTrayLabelItemVerticalPaddingVeriticalAlignment, 655 kTrayLabelItemHorizontalPaddingBottomAlignment)); 656 } 657 } 658} 659 660void TrayUser::OnUserUpdate() { 661 // Check for null to avoid crbug.com/150944. 662 if (avatar_) { 663 avatar_->SetImage( 664 ash::Shell::GetInstance()->system_tray_delegate()->GetUserImage(), 665 gfx::Size(kUserIconSize, kUserIconSize)); 666 } 667} 668 669} // namespace internal 670} // namespace ash 671