Home | History | Annotate | Download | only in user
      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 
     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 
     51 TrayUser::~TrayUser() {
     52   Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this);
     53 }
     54 
     55 TrayUser::TestState TrayUser::GetStateForTest() const {
     56   if (!user_)
     57     return HIDDEN;
     58   return user_->GetStateForTest();
     59 }
     60 
     61 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 
     69 gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const {
     70   DCHECK(user_);
     71   return user_->GetBoundsInScreenOfUserButtonForTest();
     72 }
     73 
     74 void TrayUser::UpdateAfterLoginStatusChangeForTest(user::LoginStatus status) {
     75   UpdateAfterLoginStatusChange(status);
     76 }
     77 
     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 
     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 
    111 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) {
    112   return new tray::AccountsDetailedView(this, status);
    113 }
    114 
    115 void TrayUser::DestroyTrayView() {
    116   layout_view_ = NULL;
    117   avatar_ = NULL;
    118   label_ = NULL;
    119 }
    120 
    121 void TrayUser::DestroyDefaultView() {
    122   user_ = NULL;
    123 }
    124 
    125 void TrayUser::DestroyDetailedView() {
    126 }
    127 
    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 
    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 
    238 void TrayUser::OnUserUpdate() {
    239   UpdateAvatarImage(Shell::GetInstance()->system_tray_delegate()->
    240       GetUserLoginStatus());
    241 }
    242 
    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 
    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 
    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 
    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