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/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 
     34 namespace {
     35 
     36 const int kUserLabelToIconPadding = 5;
     37 
     38 }  // namespace
     39 
     40 namespace ash {
     41 
     42 TrayUser::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 
     52 TrayUser::~TrayUser() {
     53   Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this);
     54 }
     55 
     56 TrayUser::TestState TrayUser::GetStateForTest() const {
     57   if (!user_)
     58     return HIDDEN;
     59   return user_->GetStateForTest();
     60 }
     61 
     62 gfx::Size TrayUser::GetLayoutSizeForTest() const {
     63   if (!layout_view_) {
     64     return gfx::Size(0, 0);
     65   } else {
     66     return layout_view_->size();
     67   }
     68 }
     69 
     70 gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const {
     71   DCHECK(user_);
     72   return user_->GetBoundsInScreenOfUserButtonForTest();
     73 }
     74 
     75 void TrayUser::UpdateAfterLoginStatusChangeForTest(user::LoginStatus status) {
     76   UpdateAfterLoginStatusChange(status);
     77 }
     78 
     79 views::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 
     90 views::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 
    115 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) {
    116   return new tray::AccountsDetailedView(this, status);
    117 }
    118 
    119 void TrayUser::DestroyTrayView() {
    120   layout_view_ = NULL;
    121   avatar_ = NULL;
    122   label_ = NULL;
    123 }
    124 
    125 void TrayUser::DestroyDefaultView() {
    126   user_ = NULL;
    127 }
    128 
    129 void TrayUser::DestroyDetailedView() {
    130 }
    131 
    132 void 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 
    199 void 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 
    245 void TrayUser::OnUserUpdate() {
    246   UpdateAvatarImage(Shell::GetInstance()->system_tray_delegate()->
    247       GetUserLoginStatus());
    248 }
    249 
    250 void 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 
    265 void 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 
    283 MultiProfileIndex 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 
    294 void 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